So you're writing some unit tests with Mockito and now you need to determine if a method got called.

Well then you've come to the right place. I'll show you how to do that here.

And I'll do it with a practical example. Because I'm cool like that.

The Use Case

Let's say you're working on an ecommerce application that allows customers to login. And when somebody successfully logs in, that user's info is saved in the session.

So now you need to write a test to ensure that the person's info got saved in the session after a successful login.

However, with a unit test, you don't always have access to the HttpSession object. In fact, you might not want access to that object.

In that situation, you've decided to just verify that the application called the method that saves customer data in the session. That's it.

Let's get started.

DAOing in Your Arms Tonight

Let's keep things simple for the sake of this guide. First, create a pretend data access object (DAO) like so:

public class CustomerDao {
	
	public Customer login(String username, String password) {
		Customer customer = new Customer();
		return customer;
	}
}

That login() method lets any user in. Again: we're keeping it simple here to focus on Mockito.

In a real application, you'd code that login() method to validate the user's credentials and return the appropriate Customer object in the event of a successful login. If the credentials aren't valid, the method would throw an exception.

Right now, the method just returns an empty Customer object.

Excellent Service

As is the case with many other applications, this one uses a service to access the DAO. Here's what that code looks like:

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

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

The service manually instantiates the DAO in the first line. Usually, though, you'd use Spring's @Autowired to handle that.

But again: we're keeping it simple and without frameworks here.

The login() method delegates the actual login process to the DAO. That makes sense.

But then it invokes the saveInSession() method. That's the method that handles actually saving the customer data in the user's session. Here's it's empty because you don't need to implement the method to test that it got called.

And remember: that's all you're testing. That the method got called.

POM Reader

Next, take a look at the dependencies you'll need in your POM file:

<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>

As of this writing, those are the latest and greatest versions of the dependencies. You probably won't need the latest and greatest, though.

So feel free to try to run this code with downlevel versions. 

Testing Time

Next, take a look at the actual test code:

@ExtendWith(MockitoExtension.class)
public class LoginServiceTest {

	@Spy
	LoginService loginService;

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

First of all, pay attention to the @Spy annotation. That means the code is using a spy instead of a mock.

And that makes sense here because there's no actual database integration happening. But even if there were, you'd probably still opt for a spy.

Why? Because then you could just stub out the methods that integrate with downstream services or databases while leaving the other methods alone.

Anyhoo, the only method here is testSuccessfulLogin(). The first line in that method performs the login using arbitrary credentials.

But the second line is what brought you here. That's the line that verifies that the saveInSession() method got called.

It does that with the assistance of a method intuitively named verify()

Verification Process

The Mockito.verify() method (or just plain verify() if you go the static import route) verifies that a method got called. 

And that's it. That's all it does.

It doesn't verify any returned values. It doesn't check for any kind of object equality.

It just verifies that a method got called.

Unsurprisingly, though, that method can't be private. That's why I've "cheated" a little bit here and given the saveInSession() method a package-level modifier.

(I've always liked that hack when it comes to testing non-public methods.)

But let's continue. The verify() method accepts a single parameter: the spy or mock that's going to get checked.

In the example above, it's: Mockito.verify(loginService) because the code needs to check the LoginService spy to ensure that a specific method got called.

Which method? Well that's what you see after the second period:

Mockito.verify(loginService).saveInSession

It's the saveInSession() method.

But that method accepts a parameter. It's a Customer object.

So you need to specify that it got called with any Customer object. That's sufficient for the purposes of this test.

And here's what that code looks like:

Mockito.verify(loginService).saveInSession(Mockito.any(Customer.class));

That's the whole line.

Now run that unit test and it should give you no errors or failures.

Wrapping It Up

Awesome. Now you know how to use Mockito to verify that a method got called.

It's up to you to take what you've learned here and put it in your own unit tests. Feel free to tinker around with the code above to run different experiments.

Have fun!

Photo by Anna Shvets from Pexels