So you're running unit tests with Mockito and you need to know that a method got executed a specific number of times? 

Okay. You can do that.

And in this guide, I'll show you how.

The Use Case

Suppose you're developing an ecommerce solution that allows users to login as customers. When they successfully login, the application stores user data in the session.

Now you need to write a test to ensure that the user data got stored in the session.

But there's a catch: you might not have access to the HttpSession object within your unit test code. So instead you want to make sure that the method that stores user data gets run.

However, you want to make sure that it gets run only once.

John DAO

The application you're working with uses the data access object (DAO) pattern. Here's a simplified version of what that code looks like:

public class CustomerDao {
	
	public Customer login(String username, String password) {
		if ("joe".equals(username) && "password".equals(password)) {
			Customer customer = new Customer();
			return customer;	
		}
		
		return null;
	}
}

The application checks the username and password. If it's a match, then it returns an empty Customer object.

Otherwise, it returns null.

Keep in mind: this is a very rudimentary version of a DAO that you're using for testing purposes only. If this were a real-world application, that login() method would go out to the database to validate the user's credentials.

Service Oriented

Next, take a look at the code for LoginService.

public class LoginService {
	
	private CustomerDao customerDao = new CustomerDao();

	public Customer login(String username, String password) {
		Customer customer = customerDao.login(username, password);
		if (customer != null) saveInSession(customer);
		
		return customer;
	}
	
	void saveInSession(Customer customer) {
		//logic to save the customer info in the session
	}
}

That class leans on the DAO you just saw. It gets instantiated the old-fashioned way here, but in a real application you'd probably use Spring's @Autowired to handle that with dependency injection.

The login() method delegates the actual login process to the DAO. If the login is successful, that DAO will return a Customer object. If it's not successful, the DAO will return null.

Now take a look at the second line in the login() method and you'll see that the saveInSession() method only gets called if the Customer object is null. In other words, it only gets called in the event of a successful login.

That saveInSession() method, by the way, handles the task of putting the user data in the session. Here, the method doesn't do anything because that's not needed for this test.

So the point of your test is to make sure the saveInSession() method got called exactly once when there's a successful login.

Depending on Dependencies

Here's what the POM file looks like for this project:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>us.careydevelopment.mockito</groupId>
	<artifactId>CrudApp</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	
	<dependencies>
		<dependency>
		    <groupId>org.mockito</groupId>
		    <artifactId>mockito-junit-jupiter</artifactId>
		    <version>4.2.0</version>
		    <scope>test</scope>
		</dependency>
		<dependency>
		    <groupId>org.junit.jupiter</groupId>
		    <artifactId>junit-jupiter-api</artifactId>
		    <version>5.8.0</version>
		    <scope>test</scope>
		</dependency>
	</dependencies>
</project>

You'll need those dependencies as well. However, if you're using Spring, chances are good that you already have them.

Note: even if you don't have the same versions, you've probably got recent enough versions that the test case here will still run.

The Actual Test

After all that, it's time to look at some unit test code. Here ya go:

@ExtendWith(MockitoExtension.class)
public class LoginServiceTest {

	@Spy
	LoginService loginService;
	
	@Test
	public void testSuccessfulLogin() {
		loginService.login("joe", "password");
		Mockito.verify(loginService, Mockito.times(1)).saveInSession(Mockito.any(Customer.class));
	}
}

First of all, take note of the fact that the code uses a spy instead of a mock. That's fine in this situation because there's no integration happening in the application.

Also: you need to run the real methods here. Not stubbed ones.

In a real-world scenario, you'd stub out the methods that integrate with downstream services or databases.

The class above has only one method: testSuccessfulLogin(). In the first line of that method, the code logs in to the application with valid credentials.

But the second line is what brought you here. It verifies that the saveInSession() method got executed one and only one time.

V Is for Verify

Here's the relevant line of code:

Mockito.verify(loginService, Mockito.times(1)).saveInSession(Mockito.any(Customer.class));

That Mockito.verify() method is what you'll use to verify that a method got executed.

But it lets you do more than that. You can also verify how many times the method got executed. That's what the code above does.

You can learn more about the Mockito verification process in my original guide on the subject. So here I'll just cover that second parameter in the verify() method.

It's a VerificationMode object. It's what you use to determine how many times a method ran.

In the code above, it's instantiated with Mockito.times(1)

And I think that's fairly self-explanatory. It means that the code will check to make sure that the method got executed one time.

That's it. Now run that unit test and it should pass.

Wrapping It Up

There you have it. Now you can verify that a method ran a specific number of times with Mockito.

But you're going to have to take what you've learned here and incorporate it into your own unit tests. So feel free to take that next step now.

Have fun!

Photo by Engin Akyurt from Pexels