Mockito- mock field in class - unit-testing

I have got a question connected with Mockito framework. Is there any way to mock a field inside a class? Lets say we have got:
#Component
public class A{
#Autowired
B b;
public methodExample(){b.doSth();}
}
class C {
#Autowired
A a;
}
#Test
public void testMethodExample(){...}
}
Is there any possibility to mock B object in order to impose return value of method doSth? I know I can pass mocked object as an argument of constructor but I wonder if there is any other option?

You may take a look at #InjectMocks.
With this annotation Mockito will try to assign the mocks through constructor, property and field, respectively, stopping at the first approach which succeeds.
Thus a unit test for your scenario might look like:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith( MockitoJUnitRunner.class )
public class c
{
#InjectMocks
A a;
#Mock
B b;
#Test
public void testMethodExample()
{
a.methodExample();
}
}
Some points worth some attention:
#InjectMocks will only take into account the fields annotated with #Mock
It's necessary to use MockitoJUnitRunnerOR call org.mockito.MockitoAnnotations.initMocks(this); in order to create and inject your mocks.

You can provide a protected setter for testing only and have your test package structure mirror the package structure of your main code.
Or you can use the Powermock extension to mock private/protected fields as required.
See
https://code.google.com/p/powermock/wiki/BypassEncapsulation
#Test
public void testDoSomething(){
A a = new A();
B mockedB = //create a mock;
Whitebox.setInternalState(a, "b", mockedB);
}

Related

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

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

How to write unit tests for classes with CheckedProviders in their constructors

I have a class under test whose constructer looks like this :
public class ClassUnderTest {
ClientOne clientOne;
ClientTwo clientTwo;
OtherDependency otherDependency;
#Inject
public ClassUnderTest(MyCheckedProvider<ClientOne> myCheckedProviderOne,
MyCheckedProvider<ClientTwo> myCheckedProviderTwo,
OtherDependency otherDependency) throws Exception {
this.clientOne = myCheckedProviderOne.get();
this.clientTwo = myCheckedProviderTwo.get();
this.otherDependency = otherDependency;
}
.
.
.
}
And the CheckedProvider looks thus :
public interface MyCheckedProvider<T> extends CheckedProvider<T> {
#Override
T get() throws Exception;
}
I could mock the clients, but how do I initialise the providers with my mocked clients.I use a combination of junit and mockito for writing tests.Any inputs would be appreciated.
What you could do is to mock providers rather than clients. ClientOne and ClientTwo are the types you are passing into your generic class, they are not variables and hence not something you want to mock. In contrast, the providers you are passing to the constructor are really variables, and what you need to control (simulate) are the behaviors of these variables.
public class ClassTest {
private static final CientOne CLIENT_ONE = new ClientOne();
private static final ClientTwo CLIENT_TWO = new ClientTwo();
#Mock
private MyCheckedProvider<ClientOne> providerOne;
#Mock
private MycheckedProvider<ClientTwo> providerTwo;
private ClassUnderTest classUnderTest;
#Before
public void setUp() {
when(providerOne.get()).thenReturn(CLIENT_ONE);
when(providerTwo.get()).thenReturn(CLIENT_TWO);
classUnderTest = new ClassUnderTest(providerOne, providerTwo, otherDependency);
}
}
As the other answer suggests, you could easily mock the providers, too.
But youMyCheckedProvider don't have to.
You already have an interface sitting there, so what would prevent you from creating something like
class MyCheckedProviderImpl<T> implements MyCheckedProvider<T> {
and that think takes a T object in its constructor and returns exactly that?
That is more or less the same what the mocking framework would be doing.

Why do I have to extend PowerMockTestCase?

The below test throws java.lang.IllegalStateException: no last call on a mock available when I don't extend from the PowerMockTestCase.
The error disappears as soon as I extend from PowerMockTestCase. Why exactly is this happening?
import static org.junit.Assert.assertEquals;
import org.easymock.EasyMock;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;
#PrepareForTest({ IdGenerator.class, ServiceRegistartor.class })
public class SnippetTest extends PowerMockTestCase{
#org.testng.annotations.Test
public void testRegisterService() throws Exception {
long expectedId = 42;
// We create a new instance of test class under test as usually.
ServiceRegistartor tested = new ServiceRegistartor();
// This is the way to tell PowerMock to mock all static methods of a
// given class
PowerMock.mockStatic(IdGenerator.class);
/*
* The static method call to IdGenerator.generateNewId() expectation.
* This is why we need PowerMock.
*/
EasyMock.expect(IdGenerator.generateNewId()).andReturn(expectedId).once();
// Note how we replay the class, not the instance!
PowerMock.replay(IdGenerator.class);
long actualId = tested.registerService(new Object());
// Note how we verify the class, not the instance!
PowerMock.verify(IdGenerator.class);
// Assert that the ID is correct
assertEquals(expectedId, actualId);
}
}
While using PowerMock for static mocking, there is a class level instrumentation happening to make your mocking work. PowerMockTestCase class has a code (method beforePowerMockTestClass()) to switch your regular class loader to powermock class loader which orchestrates mocking injection. Hence you need to extend this class for static mock to work.
You need to have the PowerMock class-loaders configured so that the static classes can be intercepted (defined using the #PrepareForTest annotation).
You don't have to extend from PowerMockTestCase. For most cases you can also configure TestNG with a PowerMockObjectFactory instead:
#PrepareForTest({ IdGenerator.class, ServiceRegistartor.class })
public class SnippetTest {
#ObjectFactory
public IObjectFactory objectFactory() {
return new PowerMockObjectFactory();
}
#org.testng.annotations.Test
public void testRegisterService() throws Exception {
...
}
}

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.

How do I test a class using JUnit 4 that extends an abstract class?

I am trying to write a unit test for a java class that is extending an abstract class? The java class looks sort of like:
public class XYZFilter extends XYZDataFilter{
#Override
protected boolean filterItem(Model d, String sector) {
//method code
return true;
}
}
The junit test class looks like:
import org.junit.Test;
import static org.junit.Assert.assertTrue;
public class XYZFilterTest {
Model m = new Model();
String sector = "SECTOR";
#Test
public void testFilterItem() throws Exception {
System.out.println("\nTest filterItem method...");
XYZFilter f = new XYZFilter();
assertTrue(f.filterItem(m, sector));
}
}
So I'm having a problem with the abstract DataFilter which is extended by the Filter class, as well as the Model class. I believe I need to mock these objects using JMockit but I am having a lot of trouble figuring out how to do this. Any advice is appreciated.
The answer is I needed to have the libraries included, JMockit doesn't handle objects in that way.