I'm trying to write unit test for my method called getBestSellers().
Here it is:
package bookstore.scraper.book.scrapingtypeservice;
import bookstore.scraper.enums.Bookstore;
import bookstore.scraper.book.Book;
import bookstore.scraper.fetcher.empik.EmpikFetchingBookService;
import bookstore.scraper.fetcher.merlin.MerlinFetchingBookService;
import bookstore.scraper.urlproperties.EmpikUrlProperties;
import bookstore.scraper.urlproperties.MerlinUrlProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import static bookstore.scraper.utilities.JSoupConnector.connect;
#Service
public class BestSellersService {
private final EmpikUrlProperties empikUrlProperties;
private final MerlinUrlProperties merlinUrlProperties;
private final EmpikFetchingBookService empikBookService;
private final MerlinFetchingBookService merlinBookService;
#Autowired
public BestSellersService(EmpikFetchingBookService empikBookService, MerlinFetchingBookService merlinBookService, EmpikUrlProperties empikUrlProperties, MerlinUrlProperties merlinUrlProperties) {
this.empikBookService = empikBookService;
this.merlinBookService = merlinBookService;
this.empikUrlProperties = empikUrlProperties;
this.merlinUrlProperties = merlinUrlProperties;
}
public Map<Bookstore, List<Book>> getBestSellers() {
Map<Bookstore, List<Book>> bookstoreWithBestSellers = new EnumMap<>(Bookstore.class);
bookstoreWithBestSellers.put(Bookstore.EMPIK, empikBookService
.get5BestSellersEmpik(connect(empikUrlProperties.getEmpik().getBestSellers())));
bookstoreWithBestSellers.put(Bookstore.MERLIN, merlinBookService
.get5BestSellersMerlin(connect(merlinUrlProperties.getMerlin().getBestSellers())));
return bookstoreWithBestSellers;
}
}
So, first I prepared test which looks like this:
package bookstore.scraper.book.scrapingtypeservice;
import bookstore.scraper.book.Book;
import bookstore.scraper.dataprovider.EmpikBookProvider;
import bookstore.scraper.dataprovider.MerlinBookProvider;
import bookstore.scraper.enums.Bookstore;
import bookstore.scraper.fetcher.empik.EmpikFetchingBookService;
import bookstore.scraper.fetcher.merlin.MerlinFetchingBookService;
import bookstore.scraper.urlproperties.EmpikUrlProperties;
import bookstore.scraper.urlproperties.MerlinUrlProperties;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
public class BestSellersServiceTest {
#Mock
private EmpikFetchingBookService empikBookService;
#Mock
private MerlinFetchingBookService merlinBookService;
#Mock
private EmpikUrlProperties empikUrlProperties;
#Mock
private MerlinUrlProperties merlinUrlProperties;
#InjectMocks
private BestSellersService bestSellersService;
#Test
public void getBestSellers() {
List<Book> merlinBestsellers = EmpikBookProvider.prepare5Bestsellers();
List<Book> empikBestsellers = MerlinBookProvider.prepare5Bestsellers();
when(empikBookService.get5BestSellersEmpik(any())).thenReturn(empikBestsellers);
when(merlinBookService.get5BestSellersMerlin(any())).thenReturn(merlinBestsellers);
//when(empikUrlProperties.getEmpik().getBestSellers()).thenReturn(anyString());
//when(merlinUrlProperties.getMerlin().getBestSellers()).thenReturn(anyString());
Map<Bookstore, List<Book>> actualMap = bestSellersService.getBestSellers();
Map<Bookstore, List<Book>> expectedMap = null;
assertEquals(expectedMap, actualMap);
assertThat(actualMap).hasSize(expectedMap.size());
}
}
Without setting behaviour for properties classes as I thought it is unnecessary, because I put any() when calling empikBookService.get5BestSellersEmpik (same for merlinBookService) but it threw NPE when calling
bookstoreWithBestSellers.put(Bookstore.EMPIK, empikBookService
.get5BestSellersEmpik(connect(empikUrlProperties.getEmpik().getBestSellers())));
I've debugged it and I have seen that
empikUrlProperties.getEmpik().getBestSellers()))
was given me NPE.
So I set behaviour like this:
when(empikUrlProperties.getEmpik().getBestSellers()).thenReturn(anyString());
when(merlinUrlProperties.getMerlin().getBestSellers()).thenReturn(anyString());
and now it is giving me here NPE with stactrace:
ava.lang.NullPointerException
at bookstore.scraper.book.scrapingtypeservice.BestSellersServiceTest.getBestSellers(BestSellersServiceTest.java:48)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
.
.
.
connect method used in tested method:
#UtilityClass
public class JSoupConnector {
public static Document connect(String url) {
try {
return Jsoup.connect(url).get();
} catch (IOException e) {
throw new IllegalArgumentException("Cannot connect to" + url);
}
}
}
Properties class (same for merlin)
package bookstore.scraper.urlproperties;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
#Getter
#Setter
#Component
#ConfigurationProperties("external.library.url")
public class EmpikUrlProperties {
private Empik empik = new Empik();
#Getter
#Setter
public static class Empik {
private String mostPreciseBook;
private String bestSellers;
private String concreteBook;
private String romances;
private String biographies;
private String crime;
private String guides;
private String fantasy;
}
}
What am I making wrong? Why it didnt work in the first place when I put any()
There are many problems, but the main one is that you're misunderstanding how mocking, argument evaluation and any() work.
You're using
when(empikBookService.get5BestSellersEmpik(any())).thenReturn(empikBestsellers);
This tells the mock empikBookService than whenever its get5BestSellersEmpik method is called, it should return empikBestsellers, whetever the argument passed to the method is.
What does your actual code pass as argument when executing your test? It passes the value returned by
connect(empikUrlProperties.getEmpik().getBestSellers())
The key part is that this expression is evaluated first, and then its result is passed as argument to the get5BestSellersEmpik() method.
Just like when you do
System.out.println(a + b)
a + b is first evaluated. If the result is 42, then the value 42 is passed to println(), and println prints 42.
So, in order for your test not to fail, the expression
connect(empikUrlProperties.getEmpik().getBestSellers())
must be evaluated successfully. Its result doesn't matter, since you've configure your mock to accept any argument. But that's irrelevant.
You're trying to do
when(empikUrlProperties.getEmpik().getBestSellers()).thenReturn(anyString());
That doesn't make any sense.
First, because empikUrlProperties.getEmpik() will return null, since empikUrlProperties is a mock, and mocks return null by default. And null.getBestSellers() will thus cause a NullPointerException.
Second, because telling a mock that it should return any string doesn't make sense. If you don't care about the string it should return, then choose a string by yourself, and make it return that. anyString() actually returns null, so you're telling it to return null.
So you need to fix that. Always think about what your code is doing instead of trying to apply a recipe.
And finally, your test also calls connect(...), which is a staic method, that you haven't (and can't) mock. This method will be called too. And it tries to connect to an actual URL. So if nothing is responding during your test at that URL, that won't work either. This connect() method should really be part of a dependency of your service, and this dependency should be mocked.
When you set your mock :
when(empikUrlProperties.getEmpik().getBestSellers()).thenReturn(anyString());
You have mocked empikUrlProperties, which is great, BUT you have not told that mock what to do when getEmpik() is called on it. Consequently, that method call will return null both here in the test, and also (before you had this line) in the production code - so this is the cause of your NPE when getBestSellers() is called.
Consequently, set that mock up, something like :
#Mock
private EmpikUrlProperties empikUrlProperties;
#Mock
private EmpikUrlProperties.Empik empikMock;
when(empikUrlProperties.getEmpik()).thenReturn(empikMock);
when(empikMock.getBestSellers()).thenReturn(anyString());
Related
I wanted to write unit test for my addTask method with mockito.
Here is the class that contains this method.
package controller;
import model.Task;
import model.User;
import repository.TaskActions;
import repository.UserActions;
import java.sql.SQLException;
import java.util.List;
public class ToDoEngine {
private TaskActions taskActions;
private UserActions userActions;
private User connectedUser;
public ToDoEngine(UserActions userStorage, TaskActions taskStorage) {
this.taskActions = taskStorage;
this.userActions = userStorage;
}
public boolean signIn(String username, String password) throws SQLException {
connectedUser = new User(username, password);
if (!userActions.signIn(connectedUser)) {
return false;
}
connectedUser.setID(retrieveConnectedUserID(connectedUser));
return true;
}
private int retrieveConnectedUserID(User connectedUser) throws SQLException {
return userActions.retrieveUserID(connectedUser);
}
public void addTask(String taskName) throws SQLException {
taskActions.addTask(new Task(taskName), connectedUser);
}
}
Here are my attempts. Unfortunately, I've got error. Below, I am gonna present you stacktrace:
package controller;
import model.Task;
import model.User;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import repository.TaskActions;
import repository.UserActions;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class ToDoEngineTest {
#Mock
TaskActions taskActionsMock;
#Mock
UserActions userActionsMock;
private ToDoEngine toDoEngine;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
toDoEngine = new ToDoEngine(userActionsMock, taskActionsMock);
}
#Test
public void addTask() throws SQLException {
Task taskName = new Task("wash");
User user = new User("admin","123");
toDoEngine.addTask("wash");
verify(taskActionsMock).addTask(taskName,user);
}
}
stacktrace:
Argument(s) are different! Wanted:
taskActionsMock.addTask(
Task(taskName=wash),
model.User#1b71f500
);
-> at controller.ToDoEngineTest.addTask(ToDoEngineTest.java:68)
Actual invocation has different arguments:
taskActionsMock.addTask(
Task(taskName=wash),
null
);
-> at controller.ToDoEngine.addTask(ToDoEngine.java:40)
Comparison Failure: <Click to see difference>
Argument(s) are different! Wanted:
taskActionsMock.addTask(
Task(taskName=wash),
model.User#1b71f500
);
-> at controller.ToDoEngineTest.addTask(ToDoEngineTest.java:68)
Actual invocation has different arguments:
taskActionsMock.addTask(
Task(taskName=wash),
null
);
-> at controller.ToDoEngine.addTask(ToDoEngine.java:40)
at controller.ToDoEngineTest.addTask(ToDoEngineTest.java:68)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
...
User and Task class contains hashCode and Equals method.
Task
package model;
import lombok.*;
#Getter
#Setter
#AllArgsConstructor
#ToString
#NoArgsConstructor
#EqualsAndHashCode
public class Task {
private String taskName;
}
User:
package model;
import lombok.*;
#RequiredArgsConstructor
#Getter
#Setter
#EqualsAndHashCode
public class User {
private final String name;
private final String password;
private int ID;
}
Thanks in advance for help. :D
In your test case you are attempting to verify a call onto this method:
public void addTask(String taskName) throws SQLException {
taskActions.addTask(new Task(taskName), connectedUser);
}
With this:
User user = new User("admin","123");
...
verify(taskActionsMock).addTask(taskName,user);
The failure message ...
Actual invocation has different arguments:
taskActionsMock.addTask(
Task(taskName=wash),
null
);
... tells us that the value of connectedUser in the test call is null.
Looking at your code the connectedUser member of ToDoEngine is populated by a call to the signIn() method but your test case is not invoking that method and hence connectedUser is null when addTask is invoked by your test.
So, if you don't need/want to test that the correct user is supplied to addTask then just change your verify call to: verify(taskActionsMock).addTask(taskName,null)
However, that feels like a sidestep so instead you should ensure that connectedUser is not null and is the value you supplied to the verify call in your test case.
Your verify method specifies that you expect addTask to be called with specific taskName and user objects.
verify(taskActionsMock).addTask(taskName,user);
But since your connected user is null this expectation fails.
If you do not care about the connected user you can use matchers to tell Mockito to ignore its actual value. E.G.
verify(taskActionsMock).addTask(ArgumentMatchers.eq(taskName), ArgumentMatchers.any());
Or if you do care about the user just setup your ToDoEngine to have connected user.
I'm new to all the mentioned technologies so it might be a stupid question.
We have a spring boot application where we need to write to a PostgreSQL-Database via JDBC.
Therefore we need the static DriverManager.getConnection() method to open the connection.
Now in my unit tests I don't want to call this class directly.
Instead I want to check, that the DriverManager.getConnection() is called with the correct String as that is my expected observable external behavior.
I encapsulated this behavior into a ConnectionFactory with the method newConnection(ConnectionType.POSTGRESQL) because we got more than one Database to use in this Application.
Now I can't find a way to verify via Mockito that this external dependency was called with the correct String like you could with an instance:
DriverManager dm = mock(DriverManager);
connectionFactory.newConnection(ConnectionType.POSTGRESQL);
verify(dm).getConnection("theConnectionStringToBeExpected");
So how to do this with the static dependency?
I tried the Captor-way but this seems to only work for direct usage like
mockStatic(DriverManager.class);
final ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
// What I have to do to verify
DriverManager.getConnection("theActualConnectionString");
// What I would like to do to verify
// connectionFactory.newConnection(ConnectionType.POSTGRESQL);
verifyStatic();
StaticService.getConnection(captor.capture());
assertEquals("theExpectedConnectionString", captor.getValue());
Edit:
Here is the nasty little workaround which I currently use for another server...
public void driverManagerIsCorrectlyCalledForAds() throws Exception {
mockStatic(DriverManager.class);
doNothing().when(databaseDriverLoader).load();
final Connection expectedConnection = mock(Connection.class);
when(DriverManager.getConnection("jdbc:extendedsystems:advantage://server:1337/database_name;user=user;password=password;chartype=ansi"))
.thenReturn(expectedConnection);
Connection actualConnection = connectionFactory.newConnection(ConnectionType.ADS);
assertEquals(expectedConnection, actualConnection);
}
Edit 2:
TestClass:
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.test.context.junit4.SpringRunner;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.*;
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringRunner.class)
#PrepareForTest({ConnectionFactory.class, DriverManager.class, DatabaseDriverInformation.class})
public class ConnectionFactoryTest {
#InjectMocks
ConnectionFactory connectionFactory;
#Mock
DatabaseDriverInformation databaseDriverInformation;
#Mock
DatabaseProperties databaseProperties;
#Mock
DatabaseProperties.Pg pg;
#Mock
DatabaseDriverLoader databaseDriverLoader;
#Before
public void setUp() {
doReturn(pg).when(databaseProperties).getPg();
doReturn("server").when(ads).getServer();
doReturn(1338).when(ads).getPort();
doReturn("database_name").when(ads).getDatabasename();
doReturn("user").when(ads).getUser();
doReturn("password").when(ads).getPassword();
}
#Test
public void driverManagerIsCorrectlyCalledForPg() throws Exception {
mockStatic(DriverManager.class);
doNothing().when(databaseDriverLoader).load();
Connection expectedConnection = mock(Connection.class);
when(DriverManager.getConnection("jdbc:postgresql://server:1338/database_name;user=user;password=password"))
.thenReturn(expectedConnection);
Connection actualConnection = connectionFactory.newConnection(ConnectionType.POSTGRESQL);
assertEquals(expectedConnection, actualConnection);
}
}
Class under Test:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.*;
#Service()
public class ConnectionFactory {
#Autowired
private DatabaseDriverLoader databaseDriverLoader;
#Autowired
DatabaseProperties databaseProperties;
public Connection newConnection(ConnectionType connectionType) {
databaseDriverLoader.load();
final String connectionString = connectionStringFor(connectionType);
try {
return DriverManager.getConnection(connectionString);
} catch (SQLException sqlException) {
throw new RuntimeException("Couldn't connect to Server");
}
}
private String connectionStringFor(ConnectionType connectionType) {
switch (connectionType) {
case ADS:
return this.adsConnectionString();
case POSTGRESQL:
return this.pgConnectionString();
default:
throw new RuntimeException("Invalid connection Type requested!");
}
}
private String adsConnectionString() {
return new StringBuilder()
.append("jdbc:extendedsystems:advantage://")
.append(databaseProperties.getAds().getServer())
.append(":")
.append(databaseProperties.getAds().getPort())
.append("/")
.append(databaseProperties.getAds().getDatabasename())
.append(";user=")
.append(databaseProperties.getAds().getUser())
.append(";password=")
.append(databaseProperties.getAds().getPassword())
.append(";chartype=ansi")
.toString();
}
private String pgConnectionString() {
return new StringBuilder()
.append("jdbc:postgresql://")
.append(databaseProperties.getPg().getServer())
.append(":")
.append(databaseProperties.getPg().getPort())
.append("/")
.append(databaseProperties.getPg().getDatabasename())
.append("?user=")
.append(databaseProperties.getPg().getUser())
.append("&password=")
.append(databaseProperties.getPg().getPassword())
.toString();
}
}
I removed the package-names, some specific imports and some unnecessary tests which are working.
After some search I found this: How to verify static void method has been called with power mockito
In Essence:
first:
mockStatic(ClassWithStaticFunctionToVerify.class)
second:
Execute the Code that will call the function you want to verify later
third:
verifyStatic();
ClassWithStaticFunctionToVerify.functionYouWantToVerify("ParameterValueYouExpect");
With it's help I got the following Solution which works fine:
#Test
public void driverManagerIsCorrectlyCalledForPg() throws Exception {
// Arrange
mockStatic(DatabaseProperties.Pg.class);
doReturn(pg).when(databaseProperties).getPg();
doReturn("server").when(pg).getServer();
doReturn(1338).when(pg).getPort();
doReturn("database_name").when(pg).getDatabasename();
doReturn("user").when(pg).getUser();
doReturn("password").when(pg).getPassword();
mockStatic(DriverManager.class);
doNothing().when(databaseDriverLoader).loadAdsDriverClass();
doNothing().when(databaseDriverLoader).loadPgDriverClass();
when(DriverManager.getConnection(anyString())).thenReturn(expectedConnection);
// Act
connectionFactory.newConnection(ConnectionType.POSTGRESQL);
// Assert
verifyStatic();
DriverManager.getConnection("jdbc:postgresql://server:1338/database_name?user=user&password=password");
}
Here is probably a simple question, but I can't get Dao Mocks to work.
import com.feetme.backend.jdbi.IRecordDAO;
import com.feetme.backend.representations.Record;
import io.dropwizard.testing.junit.ResourceTestRule;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class BasicResourceTest {
private static final IRecordDAO dao = mock(IRecordDAO.class);
private final Record record = getDummyRecord();
#ClassRule
public static final ResourceTestRule resources = ResourceTestRule.builder()
.addResource(new BasicResource(dao))
.build();
private static Record getDummyRecord(){
Record rec = new Record();
rec.setId(10);
return rec;
}
#Before
public void setup() {
when(dao.findRecordById(eq(10))).thenReturn(record);
reset(dao);
}
#Test
public void testGetId_Patient() {
Record r = dao.findRecordById(10);
assertThat(r).isEqualTo(record);
assert(r.getId() == 10)
}
In this case, both my asserts are never ok.
I also trier to put the reset call in the #After method. Same problem.
My IRecordDAO method normally simply fetches a Record in DB.
I probably missed something obvious.
Any help would be appreciated.
Here the DAO interface.
#RegisterMapper(RecordMapper.class)
public interface IRecordDAO {
#SqlQuery("sql query ...")
Record findRecordById(#Bind("id") long id);
/**
* close with no args is used to close the connection
*/
void close();
Edit: Actually the problem seems related to the eq() method. When I do something similar with a method of my dao that does not require any parameter, I don't have any problem.
When I replace eq(10) by anyInt() it works fine. I think I'll be fine with it for now but any clue is still welcome.
Finally, replacing eq(10) by 10 works fine. How is eq supposed to be used then ?
Don't reset(dao) in your setup() method. This is causing the mock dao to forget your previously configured stubbing. See the Mockito documentation on resetting mocks.
According to eq's java doc
public static <T> T eq(T value)
Object argument that is equal to the given value.
it's for Objects, while 10 is int which is a primitive type. You could try using new Integer(10), just to see if that makes any difference.
Given this target code:
...
sessionWrapper.execute(arenaCreateCql, arenaGuid, arenaName, displayName, authorName, createdOn);
...
And Mockito code to validate that line:
...
#Captor
private ArgumentCaptor<Date> createdOnCaptor;
...
#Test
public void testThat_Execute_CreatesNewArena() throws Exception {
...
inOrder.verify(mockSessionWrapper).execute(
eq(arenaCreateCql), eq(testArenaGuid), eq(testArenaName), eq(testArenaDisplayName), eq(testAuthorName), createdOnCaptor.capture());
...
assertNotNull(createdOnCaptor.getValue());
}
This works using Mockito 1.9.5. When upgrading 1.10.8, the verify passes, but the getValue() fails with this error:
org.mockito.exceptions.base.MockitoException:
No argument value was captured!
You might have forgotten to use argument.capture() in verify()...
...or you used capture() in stubbing but stubbed method was not called.
Be aware that it is recommended to use capture() only with verify()
Edit to add MCVE. The following code runs green with Mockito 1.9.5, red with Mockito 1.10.8.
MockitoExample.java:
package org.makeyourcase.example;
import java.util.Date;
public class MockitoExample {
private MockitoExampleExecutor executor;
public void execute(){
executor.execute("var1", new Date());
}
}
MockitoExampleExecutor.java:
package org.makeyourcase.example;
public class MockitoExampleExecutor {
public void execute(Object... bindVariables){
}
}
MockitoExample_UT:
package org.makeyourcase.example;
import java.util.Date;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
#RunWith(MockitoJUnitRunner.class)
public class MockitoExample_UT {
#Mock
private MockitoExampleExecutor mockitoExampleExecutor;
#Captor
private ArgumentCaptor<Date> dateCaptor;
#InjectMocks
private MockitoExample subject;
#Test
public void testThat_Execute_InvokesCalendar() throws Exception {
subject.execute();
verify(mockitoExampleExecutor).execute(eq("var1"), dateCaptor.capture());
assertNotNull(dateCaptor.getValue());
}
}
One other piece of info came to light as a result of creating the MCVE - the test works fine if the Date is the only element passed for bindVariables. That is, remove "var1" from target and test code, then the test runs fine under 1.9.5 and 1.10.8. Also, it doesn't matter that the captor is for a Date. The same issue occurs if the parameter is of another type, such as Integer.
Thanks, this is probably a bug, I've created the report on GH-188.
Not sure when it will be fixed though. Fixed in GH-211.
Suppose I have a class like so:
public class StaticDude{
public static Object getGroove() {
// ... some complex logic which returns an object
};
}
How do I mock the static method call using easy mock? StaticDude.getGroove().
I am using easy mock 3.0
Not sure how to with pure EasyMock, but consider using the PowerMock extensions to EasyMock.
It has a lot of cool functions for doing just what you need -
https://github.com/jayway/powermock/wiki/MockStatic
Easymock is a testing framework for "for interfaces (and objects through the class extension)" so you can mock a class without an interface. Consider creating an interfaced object with an accessor for your static class and then mock that acessor instead.
EDIT: Btw, I wouldn't recommend doing static classes. It is better to have everything interfaced if you are doing TDD.
Just in Case PowerMock is unavailable for any reason:
You could move the static call to a method, override this method in the instantiation of the tested class in the test class, create a local interface in the test class and use its method in the overidden method:
private interface IMocker
{
boolean doSomething();
}
IMocker imocker = EasyMock.createMock(IMocker.class);
...
#Override
void doSomething()
{
imocker.doSomething();
}
...
EasyMock.expect(imocker.doSomething()).andReturn(true);
Generally speaking, it is not possible to mock a static method without using some sort of accessor, which seems to defeat the purpose of using a static method. It can be quite frustrating.
There is one tool that I know of called "TypeMock Isolator" which uses some sort of Satanic Magic to mock static methods, but that tool is quite expensive.
The problem is, I know of no way to override a static method. You can't declare it virtual. you can't include it in an interface.
Sorry to be a negative nelly.
Adding an exemple on how to implements static mock along regular mock of injected classes with EasyMock / PowerMock, since the linked exemple only shows static mock.
And with the PowerMockRunner the #Mock services are not wired on the #TestSubject service to test.
Let say we have a service we want to test, ServiceOne :
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class ServiceOne {
#Autowired
private ServiceTwo serviceTwo;
public String methodToTest() {
String returnServ2 = serviceTwo.methodToMock();
return ServiceUtils.addPlus(returnServ2);
}
}
Which calls another service that we will want to mock, ServiceTwo :
import org.springframework.stereotype.Service;
#Service
public class ServiceTwo {
public String methodToMock() {
return "ServiceTwoReturn";
}
}
And which calls a final class static method, ServiceUtils :
public final class ServiceUtils {
public static String addPlus(String pParam) {
return "+" + pParam;
}
}
When calling ServiceOne.methodToTest() we get "+ServiceTwoReturn" as a return.
Junit Test with EasyMock, mocking only the injected ServiceTwo Spring service :
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import org.easymock.EasyMockRunner;
import org.easymock.Mock;
import org.easymock.TestSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
#RunWith(EasyMockRunner.class)
public class ExempleTest {
#TestSubject
private ServiceOne serviceToTest = new ServiceOne();
#Mock
private ServiceTwo serviceMocked;
#Test
public void testMethodToTest() {
String mockedReturn = "return2";
expect(serviceMocked.methodToMock()).andReturn(mockedReturn);
replay(serviceMocked);
String result = serviceToTest.methodToTest();
verify(serviceMocked);
assertEquals("+" + mockedReturn, result);
}
}
Junit Test with EasyMock & PowerMock, mocking the injected ServiceTwo Spring service but also the final class and its Static method :
import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertEquals;
import static org.powermock.api.easymock.PowerMock.createMock;
import static org.powermock.api.easymock.PowerMock.mockStatic;
import static org.powermock.reflect.Whitebox.setInternalState;
import org.easymock.Mock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(ServiceUtils.class)
public class ExempleTest {
private ServiceOne serviceToTest;
private ServiceTwo serviceMocked;
#Before
public void setUp() {
serviceToTest = new ServiceOne();
serviceMocked = createMock(ServiceTwo.class);
// This will wire the serviced mocked into the service to test
setInternalState(serviceToTest, serviceMocked);
mockStatic(ServiceUtils.class);
}
#Test
public void testMethodToTest() {
String mockedReturn = "return2";
String mockedStaticReturn = "returnStatic";
expect(serviceMocked.methodToMock()).andReturn(mockedReturn);
expect(ServiceUtils.addPlus(mockedReturn)).andReturn(mockedStaticReturn);
PowerMock.replayAll();
String result = serviceToTest.methodToTest();
PowerMock.verifyAll();
assertEquals(mockedStaticReturn, result);
}
}