Last month I posted about a major update I made for my testing framework. A lot of new functionality was rolled in, and the execution of the tests was significantly cleaned up. My co-worker Marco also merged in some changes, making the project Gradle friendly. The more I use this tooling, the more I like it (but I wrote it, so that seems about right). However, I’ve noted the need to expand it for further usage. I’ve been using this framework for a few projects to perform acceptance and regression testing (via Selenium), but I wanted to do more. I’ve always stated this framework is optimized for Selenium, but can do anything, so that’s what I did.

For a project I was working on, we wanted to add in some smoke tests. This was your typical web application, and we decided exercising the APIs was the best way to quickly verify the application was up/ready for testing. We had all of the APIs defined, so I simply wanted to make calls, and verify the responses. I ended up writing a class specifically for this, that complimented the testing framework. Using this class, I could simply create a new instance, make some API calls using it, and then verify the output. All of this was logged in the same way the Selenium calls were, with expected and actual JSON comparisons.

This class was written to compare JSON responses provided by the services. There is not reason this class couldn’t be changed by the user (i.e. YOU) to parse/compare XML results, but since our services replied solely with JSON, we didn’t include this extra capability.

Making a simple call of

service = new WebServices(String site, String username, String password);

Is enough to setup the class. Providing the Services class with a site, username, and password, allowed us to initially log into the system once, and save an XSRF token. This meant that any future test wouldn’t need to worry about logging in – think less repetitive steps in tests. Several different methods exist, to check different things about the responses. The class supports 4 different API methods: GET, POST, DELETE, PUT, with each one able to check the response code or message. For example:

checkHTTPGetCode(TestOutput output, String urlStr, HashMap<String, String> params);          //default to check for response code 200
checkHTTPDeleteCode(TestOutput output, String urlStr, HashMap<String, String> params, int expectedResponseCode);
checkHTTPPostResponse(TestOutput output, String urlStr, HashMap<String, String> params, String expectedResponse);
checkHTTPPutResponseExcludeFields(TestOutput output, String urlStr, HashMap<String, String> params, List<String> excludedFields, String expectedResponse);

Similar to the Selenium tests, these tests can be parameterized as well.

@DataProvider(name = "budgets", parallel = true)
public Object[][] PerformanceOptions(Method method, ITestContext test) {
	List<Object> dp = new ArrayList<Object>();
	for (Budgets budget : Budgets.values()) {
		dp.add(new Object[] { budget, method, test });
	}
	return dp.toArray(new Object[dp.size()][]);
}
@Test(dataProvider = "budgets", description = "A test to check '/summary' api for the past month")
public void checkSummaryOneMonth(Budgets budget,
		Method method, ITestContext test) throws Exception {
	String testName = getTestName(method, budget);
	TestOutput output = (TestOutput) test.getAttribute(testName + "Output");
	int errors = (Integer) test.getAttribute(testName + "Errors");

	// calculate our expected expenses
	String expected = "{\"id\":123,\"name\":\"some name\",\"elements\":[{\"id\":1,\"name\":\"some name\"},{\"id\":2,\"name\":\"some other name\"}]}";
	// generate our params
	HashMap<String, String> params = new HashMap<String, String>;
	params.put("budget_level", String.valueOf(budget.getID()));
	errors += service.checkHTTPGetResponse(output, apiURL, params, expected);

	// finalize our tests
	genFun.stopTest(output, errors);
}

You’ll notice this looks practically identical to the Selenium tests that were run, just making calls to the service class instead of selHelper.

While this service class was tailored for our particular authentication scheme, it can be easily modified to fit any scheme. The full source code of the class is located on github, in the test/tools directory.

Drop me a line on your thoughts, and until then, happy coding!

Leave a comment

Your email address will not be published. Required fields are marked *

X