Up and running with: Mockito

This is the third article in our series on new, popular or otherwise interesting tools used in test automation. You can read all posts within this series by clicking here.

What is Mockito?
Mockito is an open source testing framework for Java that allows developers to create mock objects for use in automated unit tests. It is often used in the Test Driven Development and Behavior Driven Development approaches. Using Mockito mock objects, developers can mock external dependencies and ensure their code interacts with it in the expected manner.

Where can I get Mockito?
Mockito can be downloaded from this site.

How do I install and configure Mockito?
As the Mockito framework consists of just a single .jar file, all you need to do is to add this .jar as a dependency to your Java project and you’re ready to start mocking!

Creating a first Mockito mock object
Before we can start creating mock objects using Mockito, we first need a Java class for which we can mock the behavior. To illustrate the workings of Mockito I created a simple class Login, consisting of a single constructor, two String variables username and password and a single method login(username,password). The class implementation is included in the download link at the end of this post.

Now, assume that this Login class is either not readily available when you want to perform unit tests that have this class as a dependency, or that you want to emulate a certain type of behavior. To do so, let’s create a Mockito mock for the Login class:

public static Login createLoginMock() {

	// create and return a mock instance of the Login class	
	return mock(Login.class);
}

Easy, right? Now, let’s see what we can do with this mock.

Using your Mockito mock
First, let’s check whether we can interact with the methods of our mock correctly. Mockito provides a verify function for this:

public static void runVerifyTestWithMockito() {
		
	// create mock instance of the login class
	Login loginMock = createLoginMock();
		
	// call methods on the mock instance
	loginMock.setUsername("bas");
	loginMock.setPassword("ok");
		
	// verify that methods are called properly
	verify(loginMock).setUsername("bas");
	verify(loginMock).setPassword("ok");
		
	// attempt to verify a method that hasn't been called (this generates an error)
	verify(loginMock).getUsername();	
}

The last call generated an error, as we try to verify an interaction that hasn’t taken place.

Now, let’s use Mockito to stub the behavior of a method of the Login class, so that we can use our mock to simulate specific behavior in our unit tests. In Mockito, this is done using a when … thenReturn … construction:

public static void runStubTestWithMockito() {
		
	// create mock instance of the login class
	Login loginMock = createLoginMock();
		
	// stub mock behavior
	when(loginMock.login()).thenReturn("login_ok");
		
	// call mock method and verify result
	Assert.assertEquals("login_ok",loginMock.login());
}

Finally, we can also have a class method of our mock return an exception, even when the actual class implementation might not always do that. This is useful when testing exception handling in your code and is done using a when … thenThrow … construction:

public static void runExceptionTestWithMockito() {

	// create mock instance of the login class
	Login loginMock = createLoginMock();

	// have the mock return an Exception
	when(loginMock.getPassword()).thenThrow(new RuntimeException());

	// call the mock method that throws the exception
	loginMock.getPassword();
}

Useful features
I’ve showed you some of the basic features of Mockito. However, the framework offers loads more, such as:

  • Verification that a method is invoked exactly once / at least x times / never / …
  • Verification that methods are invoked in a particular order
  • Explicitly verify that certain mock classes have not been interacted with

An extensive list of Mockito features, along with examples, can be found here.

Further reading
There is a lot of documentation to be found on Mockito on the web, apart from the reading material which I’ve linked to above. For example, a nice tutorial, including using Mockito for Android testing, can be found on the site of Lars Vogel. For those that prefer actual books, Tomek Kaczanowski has written a book on Mockito and TestNG, which can be purchased here.

An Eclipse project including my Login class implementation and the tests I’ve demonstrated above can be downloaded here.

Happy mocking!

How to create screenshots in your Selenium Webdriver tests

As they say, a picture often says more than a thousand words. This also applies to test execution reports – no matter the clarity of your error messages, often a screenshot of the status of your browser instance at the moment a particular error occurs is the most efficient way to record what has gone wrong. In this post, I will show you how to generate a screenshot in Selenium Webdriver, which you can then save to disk for later reference and/or include in your custom reports.

First, we need a simple test script in which a screenshot is created at a given moment. Here it is:

public static void runTest() {

	WebDriver driver = new FirefoxDriver();

	driver.get("http://parabank.parasoft.com");

	// log in
	driver.findElement(By.name("username")).sendKeys("john");
	driver.findElement(By.name("password")).sendKeys("demo");
	driver.findElement(By.xpath("//input[@value='Log In']")).click();
		
	//create screenshot
	createScreenshot(driver,"C:\\temp\\screen.png");

	driver.quit();
}

The createScreenshot method takes two arguments: the driver instance and a physical location where the created screenshot will be stored. The implementation of this method is pretty straightforward:

public static void createScreenshot(WebDriver driver, String location) {

	// generate screenshot as a file object
	File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
	try {
		// copy file object to designated location
		FileUtils.copyFile(scrFile, new File(location));
	} catch (IOException e) {
		System.out.println("Error while generating screenshot:\n" + e.toString());
	}
}

When we run this test, we see that a screenshot is created and stored in the location we provided (in my case, C:\temp):
Screenshot as created by our code

Creating screenshots when an alert is active
One of my readers, Kritika Gupta, nicely alerted me that the method described above does not work when there is a Javascript alert active. Instead, an UnhandledAlertException is thrown and no screenshot is created. This seems to be a known issue with Selenium, as can be read here. I have found a way to circumvent this problem by using the Java Robot class. It works as follows:

public static void createScreenshotUsingRobot(WebDriver driver, String location) {
		
	BufferedImage image = null;
	try {
		image = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
	} catch (HeadlessException | AWTException e1) {
		e1.printStackTrace();
	}
	try {
		ImageIO.write(image, "png", new File(location));
	} catch (IOException e) {
		e.printStackTrace();
	}
}

When we use this method to create screenshot, it even works when Javascript alert messages are active, as can be seen in the screenshot below, which has been taken using the code above:
Screenshot taken using the Java Robot class
Please note that the code above takes a screenshot of your complete desktop (as you can see) instead of a screenshot from the active browser window only. Also, remember that this code does not take care of handling the popup. This should be done in your main test code.

The Eclipse project I used for this example can be downloaded here.

Five considerations before choosing an automated testing solution

Selecting a tool to aid your project or organisation with the implementation of automated software testing can be a daunting task. Many tools are available, each of them with its own benefits and drawbacks. The following considerations will provide you with some much-needed guidance in the test tool selection process.

What kind of technology is to be automated?
The choice for a specific automated testing tool heavily depends on the type of application(s) your tests are written for. Many tools are specifically designed for a single type of application, such as Selenium, which is targeted towards websites and web applications running in a browser. Other tools are able to handle a lot of different types of applications, such as browser applications, Windows applications and SAP. Tools that fall into the latter category tend to be more expensive, but might be the better choice if your test scripts cover different types of applications.

Do I go for open source or for commercially licensed tooling?
At first sight, going the open source route when selecting an automated testing tool might seem the most cost-effective option, due to the lack of license fees and support contract fees that typically come with commercial test tools. However, open source tools come with necessary investments of their own, as it often takes more time and more technical (programming) knowledge to set up and maintain automated test scripts. One often overlooked advantage of open source test tooling is the fact that the more popular ones are often supported a large community on the Internet. This community can be tapped into for technical support and often offers a library of additional features and extensions for the tool in case.

Do I prefer in house implementation or do I want to outsource test automation activities?
Another consideration to make is whether to have your own team implement the automated test scripts or to leave this to a third party. Keeping automated test development in house has a number of benefits, such as:

  • The people working on test automation are likely to be very familiar with the application(s) under test.
  • Knowledge gained on test automation is retained within the organisation.
  • The opportunity to work on test automation might be a good motivator for people in the organisation willing to learn something new.

On the other hand, outsourcing test automation implementation also has certain benefits, the most important being that dedicated test (automation) service providers likely have a lot of experience with the selected tool, enabling them to implement it much more efficiently.

How much training is required for the implementation of test automation?
Some tools require more technical knowledge upfront before users can successfully automate tests with it, while others do all they can to abstract from the technical details and offer an interface that makes it possible to implement and run automated tests for everybody. The former category of tools typically requires more training for them to be used. Another factor to be considered is the programming or scripting language used by the automated test tool. If, for instance, a tool is Java-based and all you have in your company are PHP developers, more training might be required than when your software development department – and the testers included in it – works with Java on a daily basis.

Does the tool match our current software testing process?
Finally, another thing worth considering is the extent to which the tool matches your current software testing process. Questions that you might want to ask with respect to this are:

  • Do the reports produced by the tool match the information requirements from the software development team and from management?
  • Does the tool integrate nicely with my current or desired automated build or continuous integration software delivery setup?
  • Can scripts be run by everybody within the software development and testing team? Note that this differs from who is going to develop the scripts.

When there is a mismatch between the features of the tool under consideration and your current software testing process, there are two further options. One is to consider a different tool that better fits the process, the other is to adapt the process to fit around the tool. The former is generally the more preferable, but in some cases where the testing tool fits the software to be tested perfectly, it might be worthwhile to adapt your testing process in some points to get a good match between the two.