public class DummyTest {
#InjectMocks
private TestService service;
#Mock
private TestRepository repository;
#BeforeEach
public void before() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testMe() {
when(repository.findAllByQuery("")).thenReturn(List.of());
List<String> entities = service.findAllByQuery("test");
verify(repository, times(1)).findAllByQuery(anyString());
}
}
class TestService {
private TestRepository repository;
public List<String> findAllByQuery(String query) {
return repository.findAllByQuery(query);
}
}
class TestRepository {
public List<String> findAllByQuery(String query) {
return List.of("");
}
}
The test above successfully passed when I do Mockito initialization via #BeforeEach annotation.
After, I tried to remove #BeforeEach annotation and initialize Mockito with #ExtendWith(MockitoExtension.class) and the test failed due to:
org.mockito.exceptions.misusing.UnnecessaryStubbingException:
org.mockito.exceptions.misusing.UnnecessaryStubbingException:
Unnecessary stubbings detected.
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
1. -> at DummyTest.testMe(DummyTest.java:33)
Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class.
Could you please explain to me, why I got so different test execution results? Technically, I have just changed the way to initialize Mockito and that all.
#ExtendWith(MockitoExtension.class) and MockitoAnnotations.initMocks(this) configures Mockito in a little different way.
When you use #ExtendWith(MockitoExtension.class) additionally configures "strictness" of Mockito with default value STRICT_STUBS.
Which means you have to change the configuration of you stubs like this:
#Test
public void testMe() {
when(repository.findAllByQuery(anyString())).thenReturn(List.of());
List<String> entities = service.findAllByQuery("test");
verify(repository, times(1)).findAllByQuery(anyString());
}
or even like this:
#Test
public void testMe() {
when(repository.findAllByQuery(eq("test"))).thenReturn(List.of());
List<String> entities = service.findAllByQuery("test");
verify(repository, times(1)).findAllByQuery(anyString());
}
Related
In my javaee project there is an interface:
public interface SomeInterface{...}
and multiple implementations:
#Stateless(name = "ImplementationA")
public class ImplementationA implements SomeInterface{...}
#Stateless(name = "ImplementationB")
public class ImplementationB implements SomeInterface{...}
In order to access all of the implementations, I have the following in an other class:
#Singelton
public class AnotherClass{
#Inject
#Any
private Instance<SomeInterface> impls;
public SomeInterface someMethod(){
for(SomeInterface imp : impls){
if(imp.oneMethod()){
return imp;
}
}
return null;
}
}
If I want to do unit test for this "AnotherClass", how do I mock the
Instance<SomeInterface> impls
field?
Tried #Mock, #Spy, could not get "impls" properly mocked from within Mockito, when the test runs, the "impls" is always null.
The Unit test itself looks like the following:
#RunWith(MockitoJUnitRunner.class)
public class SomeTestClass {
#InjectMocks
AnotherClass anotherClass;
#Spy // Here I tried #Mock as well
private Instance<SomeInterface> impls;
#Test
public void TestSomeMethod(){
Assert.assertTrue( anotherClass.someMethod() == null ); // <- NullPointerException here, which indicates the impls is null instead of anotherClass.
}
}
Had to add another method in that "AnotherClass" to accept an instance of Instance impls, which is created in unit test, which works but is ugly that another irrelevant method has to be added only for the purpose of unit test.
Any idea what the proper way of doing unit test looks like?
Mockito and Junit version:
group: 'junit', name: 'junit', version: '4.12'
group: 'org.mockito', name: 'mockito-core', version:'2.12.0'
Thanks in advance.
What you could try to do:
Add some expectations if you need them. You probably need this impls.xxxx() to call a real method if it is a Spy (guess this is default behavior).
Maybe also try to init mocks first:
#RunWith(MockitoJUnitRunner.class)
public class SomeTestClass {
#InjectMocks
AnotherClass anotherClass;
#Spy
private Instance<SomeInterface> impls;
// init here
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
#Test
public void TestSomeMethod(){
anotherClass.someMethod(); // <- NullPointerException here, which indicates the impls is null instead of anotherClass.
}
}
This init call needs to be somewhere in the base class or a test runner.
That's weird it does not work without, I guess if you use MockitoJUnitRunner it should work.
UPD:
It's been a long time but I can see there are some new comments so providing additional input.
This is the test that works.
// ImplementationA.oneMethod simply returns TRUE in my case
// ImplementationB.oneMethod simply returns FALSE
#RunWith(MockitoJUnitRunner.class)
public class AnotherClassTest {
#Spy // can be Mock
Instance<SomeInterface> impls;
#InjectMocks
AnotherClass classUnderTest;
#Mock
Iterator<SomeInterface> iterator; // why need it - check below :)
#Test
public void someMethod() {
when(impls.iterator()).thenReturn(iterator);
when(iterator.hasNext()).thenReturn(true).thenReturn(false);
when(iterator.next()).thenReturn(new ImplementationA());
SomeInterface res = classUnderTest.someMethod();
System.out.println("done");
}
}
Where was the problem ? Here:
public SomeInterface someMethod() {
// explanation: For-Each uses iterator
// if we do not mock Instance<SomeInterface> impls properly
// impls.iterator() under the hood will return NULL -> NPE
for (SomeInterface imp : impls) {
if (imp.oneMethod()) {
return imp;
}
}
return null;
}
That is why in my test I also create dummy iterator (Mock). I also need to provide some expectations to make it work and here they are:
when(impls.iterator()).thenReturn(iterator); // returns my mock
when(iterator.hasNext()).thenReturn(true).thenReturn(false);
when(iterator.next()).thenReturn(new ImplementationA());
Hope it's clear :) Having this make the for-each works fine and returns ImplementationA.
Happy Hacking :)
I am using Mockito to write a simple unit test.
Then, a function under test:
public class MyService {
public void getData() {
executor.execute(new MyRunnable() {
#Override
doTask() {
MyRestClient client = getRestClient();
Response resp = client.getFromServer();
persist(resp.getData());
}
});
}
}
protected MyRestClient getRestClient() {
return new MyRestClient();
}
My test case, I want to test doTask() has run & resp.getData() is persisted:
#Test
public void testGetData() {
MyService spyService = spy(MyService.getInstance());
// mock client
MyRestClient mockedClient = mock(MyRestClient.class);
mockedClient.setData("testData");
// stub getRestClient() function to return mocked client
when(spyService.getRestClient()).thenReturn(mockedClient);
// SUT
spyService.getData();
// run the Runnable task.
Mockito.doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation) throws Exception {
Object[] args = invocation.getArguments();
Runnable runnable = (Runnable) args[0];
runnable.doTask();
return null;
}
}).when(executor).execute(Mockito.any(Runnable.class));
...
}
As you see above, I stub the getRestClient() function to return a mocked MyRestClient. However when run the test case, it doesn't stub the getRestClient() but run the real function. Why?
[Edit] following comment and review feedback
A rule of thumb is not to mock the class under test. Also your testing will be much easier if your class under test does not use the new keyword. Instead use Factory classes to create objects. There will be no need to use Mockito.spy() only Mockito.mock().
The fact that the following answer requires significant test setup is telling you that MyService has too much reposibility and needs to be simplified. However for the sake of answering your question directly here is how you can refactor your code to support verifying the call to persist() using Mocks.
MyService accepts in the constructor the objects that you will be mocking in your test setup. Having them passed into the constructor allows your JUnit test case to create the Mocks and keep a reference to them for verification later.
public class MyService {
private MyRunnableFactory runFactory;
private MyRestClientFactory restFactory;
private MyRestDao dao;
// inject constructor arguments
public MyService(MyRunnableFactory runFactory, MyRestClientFactory restFactory, MyRestDao dao) {
this.runFactory = runFactory;
this.restFactory = restFactory;
this.dao = dao;
}
public void getData() {
MyRestClient restClient = restFactory.createInstance();
MyRunnable runner = runFactory.createInstance(restClient, dao);
executor.execute(runner);
}
}
MyRunnable is created so that it can be tested in isolation if required. Again we inject the Mock objects into the constructor. It is tempting to inline Runnables as you have written in your question, however you lose the ability to control the new instance being created within you tests.
public class MyRunnable implements Runnable {
private MyRestClient restClient;
private MyRestDao dao;
public MyRunnable(MyRestClient restClient, MyRestDao dao) {
this.restClient = restClient;
this.dao = dao;
}
public void run() {
Response resp = restClient.getFromServer();
dao.persist(resp.getData());
}
}
MyRestDao is created because this is the class that you want to Verify in your test case. I don't see where persist() is defined in your question so we create a Data Access Object (DAO) to implement it.
public class MyRestDao {
public void persist() {
// save to some repository
}
}
Now let's write the test case that uses the above classes. We want to verify that the persist() method has been called
#RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {
#Mock MyRestDao dao;
#Mock MyRestClient restClient;
#Mock MyRunnableFactory runFactory;
#Mock MyRestClientFactory restFactory;
#Test
public void testPersistIsCalled() {
Response expectedResponse = new Response("some data"); // real implementation, not mocked
MyRunnable runner = new MyRunnable(restClient, dao); // real implementation, not mocked
when(restFactory.createInstance()).thenReturn(restClient);
when(runFactory.createInstance(restClient, dao)).thenReturn(runner);
when(restClient.getFromServer()).thenReturn(expectedResponse);
when(restClient.getData()).thenReturn(myRunnable);
// method under test
MyService service = new MyService(runFactory, restFactory);
service.getData();
verify(dao).persist(expectedResponse.getData());
}
}
Note that this test case is brittle because it is tightly coupled to the actual implementation of the MyService class. Ideally you want tests that don't need to know about the internal workings of your class under test.
I am newe to Mockito and Junit, I have written unit test cases for testing my rest service and made use of Mockito for injecting mocks. And code is below:
BillControllerTest.java:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class BillControllerTest{
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#InjectMocks
private BillController billController;
#Mock
private BillService mockBillService;
#Before
public void setupController() {
MockitoAnnotations.initMocks(this);
this.mockMvc = webAppContextSetup(webApplicationContext).build();
}
#Test
public void testBills() throws Exception {
// some fake data
final List<Bill> fakeBillList = new ArrayList<>();
fakeBillList.add(CpsFake.bill("1234"));
when(mockBillService.getBills(BILL_UID))
.thenReturn(fakeBillList.stream());
mockMvc.perform(get("/bills/" + BILL_UID ))
.andExpect(content().contentType(MediaTypes.HAL_JSON))
// expect particular uid
.andExpect(content().string(containsString("\"uid\":\"1234\"")))
ApplicationTest.java:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class ApplicationTest {
#Test
public void contextLoads() {
}
}
BillController.java:
#RestController
#RequestMapping(value = "/trials/{billUid}", produces = "application/hal+json")
public class BillController extends BaseController {
#Autowired
private BillService billService;
#Autowired
public BillController(BillService billService) {
this.billService = billService;
}
#RequestMapping(method = RequestMethod.GET, value = "")
public ResponseEntity<Resources<Resource<Bill>>> getBills(#PathVariable String billUid) {
return resourceListResponseEntity(
() -> billService.getBills(billUid),
bill-> createResource(bill),
resources -> resources.add(linkTo(methodOn(BillController.class)
.getBills(billUid)).withSelfRel()));
}
When I run the test (BillControllerTest), mockBillService is not getting invoked and instead it is calling actual billService. Please help me in this issue. Thank you in advance.
I think the problem is that you use mockito together with spring. Both make use of proxys.
Looking at your code of getBills - it is not dependent on the spring application context. So skip all your spring setup code (mockMvc and webApplicationContext) and use only Mockito. If yet invisible code depends on the ApplicationContext - mock the application context rather than setting up a real one.
This test would be:
simpler
container independent
faster
You could replace initMocks with the Annotation RunWith(MockitoJUnitRunner.class) if you want.
Consider the following sample code:
#Stateless
public class MyBean {
private SomeHelper helper;
private long someField;
#PostConstruct
void init() {
helper = new SomeHelper();
someField = initSomeField();
}
long initSomeField() {
// perform initialization
}
public void methodToTest() {
helper.someMethod();
long tmp = 3 + someField;
}
}
And here is the test template, that I always use
public class MyBeanTest {
#Spy
#InjectMocks
private MyBean testSubject;
#Mock
private SomeHelper mockedHelper;
#Before
public void before() {
MockitoAnnotations.initMocks(this);
doReturn(1L).when(testSubject).initSomeField();
}
#Test
public void test() {
testSubject.methodToTest();
// assertions
}
}
The problem with testing methodToTest is that it needs field someField to be initialized. But the initialization is done in #PostConstruct method. And I can't run this method before call to testSubject.methodToTest(), because it will re-initialize helper. Also, I don't want to manually set up all the mocks. And I don't want to use reflection to set the someField, because that would make MyBeanTest vulnerable to MyBean refactoring. Can anybody propose, maybe better design to avoid situations like this?
A few notes:
Logic in initSomeField could be quite heavy (including calls to database), so I want to initialize it only once in a #PostConstruct method.
I don't want to create a setter for this field or widen its access modifier, because that would allow unwanted changes to my field.
If your test is in the same package as your class, then you can just call initSomeField directly, since it's package private. You can either do this in each individual test method, or in your #Before method, provided it runs after initMocks.
I am trying to test my gwt app with gwt junit but seems to not be able to set up things correctly to make the objectify be tested.
All the tutorials demonstrate testing DataStore but not objectify (which is higher level of data base service)
My base class for testing looks like this:
public class TestBase {
private static final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
protected static ObjectifyFactory fact;
#BeforeClass
public static void setUp() {
helper.setUp();
fact = new ObjectifyFactory() {
#Override
public Objectify begin(ObjectifyOpts opts)
{
opts.setSessionCache(false);
return super.begin(opts);
}
};
}
#AfterClass
public static void tearDown() {
helper.tearDown();
}
}
then i have classes that extends the base:
public class UserServiceTest extends TestBase{
private User inactiveUser;
private UserService us;
Objectify _ofy;
#Rule
public ExpectedException thrown = ExpectedException.none();
#Before
public void beforeTest() {
//Register the classes used in the test
fact.register(User.class);
us = new UserService();
inactiveUser = new User();
}
#Test
public void basicTest(){
Objectify ofy = ObjectifyService.begin();
ofy.put(inactiveUser); //This fails with exception: An exception occurred: com.google.apphosting.api.ApiProxy$CallNotFoundException
//My goal is to reach these test but "addUser" uses also objectify
//UserService.addUser("shpungin#gmail.com", "bye");
//assertNotNull(inactiveUser.get_id());
}
Do you have an idea of what am I doing wrong? I looked all over the Internet and found no solution (some even said to remove app-engine-sdk from .classpath but it dosent seems to work.
Thank you.
I solved this.
Although com.google.apphosting.api.ApiProxy should be part of the app-engine
Some jars still needs to be inside the .classpath :
${SDK_ROOT}/lib/testing/appengine-testing.jar
${SDK_ROOT}/lib/impl/appengine-api.jar
${SDK_ROOT}/lib/impl/appengine-api-labs.jar
${SDK_ROOT}/lib/impl/appengine-api-stubs.jar //This one I missed
Also I upgraded my app-engine to v 1.6.4.1 (maybe that also helped).