Mock Instance<Class<?>> annotated with Inject&Any in Junit - unit-testing

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

Related

Replace a bean by a mock in Helidon test

I have a Helidon application and I would like to test (part of) it.
My test is annotated with #HelidonTest, and now I would like to replace one bean by a mock (and configure this mock, use all other beans as they are found, but with the mock injected).
I did figured out how to:
Replace one bean by a test implementation (separate class): By annotating the test implementation class with #Priority(1) and #Alternative and supply it by annotating the test with #AddBean(MyBeanTestImpl.class).
But I can not create a mock (with Mockito) as an individual class.
Produce a mock(MyBean.class): By creating a producer method and annotate it with #Produces:
But it clashes with the real bean and gives: "WELD-001409: Ambiguous dependencies for type..."
When I annotate it also with #Alternative it is simply ignored.
I can not annotate it with #Priority(1), because this annotation can only be applied to types and parameters.
Any idea how I can replace one bean by a mock?
I tried setter injection to manually inject mock beans.
Class under test
#ApplicationScoped
public class SomeService {
private ExternalService externalService;
#Inject
public void setExternalService(ExternalService externalService) {
this.externalService = externalService;
}
public String doSomething() {
return externalService.getData();
}
}
Test Class
#HelidonTest
class SomeServiceTest {
#Inject
private SomeService someService;
private ExternalService externalService;
#BeforeEach
void setUp() {
externalService = Mockito.mock(ExternalService.class);
someService.setExternalService(externalService);
}
#Test
void doSomething() {
Mockito.when(externalService.getData())
.thenReturn("Mock data");
String actual = someService.doSomething();
Assertions.assertEquals("Mock data", actual);
}
}
There are also methods to mock a whole bean by mocking the constructor as well. For that, we have to make use of #Observes annotation
#HelidonTest
public abstract class HelidonTestHelper {
private MockedConstruction<ExternalService> mockedConstruction;
void init(#Priority(1) #Observes #Initialized(ApplicationScoped.class) ContainerInitialized containerInitialized) {
mockedConstruction = Mockito.mockConstruction(ExternalService.class);
//mock common beans here. This will be executed once application scope is loaded.
}
void onStop(#Priority(1) #Observes #Destroyed(ApplicationScoped.class) ContainerShutdown containerShutdown) {
//do cleanup here if needed.
mockedConstruction.closeOnDemand();
}
}
Once the above is done, instead of helidon test, you can extend the helper class we created.
class SomeServiceTest extends HelidonTestHelper {
#Inject
private SomeService someService;
#Inject //this will be a mock
private ExternalService externalService;
#Test
void doSomething() {
Mockito.when(externalService.getData())
.thenReturn("Mock data");
String actual = someService.doSomething();
Assertions.assertEquals("Mock data", actual);
}
}

Mockito method call stub not working - Mockito.doReturn(false).when(studentServiceImpl).myClass().isValidUser(ArgumentMatchers.anyInt());

adding test cases for getStudent method, this is having internal calls
1- is repository call - stubbing this call working fine
2- validate user call - stubbing this call not working, showing some error and test case failed.
Service Class
#Service
public class StudentServiceImpl implements StudentService {
#Autowired
FakeStudentRepository fakeStudentRepository;
#Override
public Optional<Student> getStudent(int id) {
Optional<Student> student = fakeStudentRepository.getStudent(id);
boolean isValid = myClass().isValidUser(student.get().getId());
if(!isValid) {
return Optional.empty();
}
return student;
}
public MyTestClass myClass() {
return new MyTestClass();
}
}
MyTestClass
public class MyTestClass {
public boolean isValidUser(int id) {
return true;
}
}
Test Class
#SpringBootTest
class StudentServiceImplTest {
#Mock
FakeStudentRepository fakeStudentRepository;
#InjectMocks
StudentServiceImpl studentServiceImpl;
#BeforeEach
public void setup() {
studentServiceImpl = Mockito.spy(StudentServiceImpl.class);
MockitoAnnotations.initMocks(this);
}
#Test
void getStudent() {
Optional<Student> student = Optional.of(Student.builder().id(1).firstName("Rahul").lastName("rahul")
.mobile("XXXXXX").build());
Mockito.doReturn(student)
.when(fakeStudentRepository).getStudent(ArgumentMatchers.anyInt());
Mockito.doReturn(false)
.when(studentServiceImpl).myClass().isValidUser(ArgumentMatchers.anyInt());
Optional<Student> resultStudent = studentServiceImpl.getStudent(student.get().getId());
assertEquals(resultStudent.get().getId(), student.get().getId());
}
}
Error
org.mockito.exceptions.misusing.WrongTypeOfReturnValue: Boolean
cannot be returned by myClass() myClass() should return MyTestClass
If you're unsure why you're getting above error read on. Due to the
nature of the syntax above problem might occur because:
1. This exception might occur in wrongly written multi-threaded tests. Please refer to Mockito FAQ on limitations of concurrency
testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
The error Message says it: You are mocking studentServiceImpl.myClass() and try to return true. It’s not possible to mock the end of a call chain as you try with your second Mockito expression.
To do what you want requires to mock myClass() first by returning a mocked class instance and mock isValidUser on that.

Mockito: stub function is not working

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.

Testing private methods in java using Powermockito

I am using PowerMockito and jUnit to write unit test cases.
public class Foo {
private String resolveApplicationId() {
return "testApplication";
}
}
Here is my test case
#RunWith(PowerMockRunner.class)
#PrepareForTest(Foo.class)
public class test{
#Before
public void prepareTest() {
foo = PowerMockito.spy(new Foo());
}
#Test
public void checkApplicationIdIsResolved() throws Exception {
PowerMockito.doNothing().when(foo, "myPrivateMethod");
PowerMockito.verifyPrivate(foo).invoke("myPrivateMethod");
//Assert Here the returned value
}
}
Please tell me
1. how can I assert the value returned by the method when it is called
2. how can I call the private method
3. if not then what actually I verify when I write test case for private methods.
Thanks.
Testing private method does not differ from testing public method. If there is no external dependencies you even don't need to create and use any mocks. The only problem is with invocation of the private method from test. This is described here or you may use spring utils.
So you don't need to mock the method you are testing. You only require to mock other objects which are not tested in this particular test. So you test would look like
#Test
public void checkApplicationIdIsResolved() throws Exception {
// makeResolveIdAccessible();
// if needed setup mocks for objects used in resolveApplicationId
assertEquals(expectedApplicationId, foo.resolveApplicationId())
}

Unit test for EJB with #PostConstruct method

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.