3

I have a very complicated class to write Junit test case. I decided to use PowerMockito since my class for which the test is to be run has a constructor initialization.

My main class is like this:

public class MainClass extends BaseClass{

MainClass(SomeClass class){
    super(class);
}

public void methodToBeTested(){
some code here
}

..few other methods which I am not going to test.
}

Now I have the test case written like this:

@RunWith(PowerMockRunner.class)
public class TestClass{

@Mock
OtherClassUsedInMainClass mock1;

@Mock
OtherClassUsedInMainClass mock2;

@InjectMocks
MainClass mainClass;

@Before
public void setUp() throws Exception{
    MockitoAnnotations.initMocks(this);
    PowerMockito.whenNew(MainClass.class).withArguments(Mockito.any(SomeClass.class))
            .thenReturn(mainClass);)
}

@Test
public void testMethodtobeTested(){
    ...I am using the other objects to mock data and test if this method works fine

    mainClass.methodtobeTested();
    \\This method will increment a value. I am just asserting if that value is right. 
    Assert.assertEquals(mainClass.checkCount(),RequiredCount)

}

}

I am getting a null pointer exception when running the Testcase since it tries to initialize the mainClass. It does not get mocked. I know I am doing something wrong. But I just don't know what it is.

Error:

org.mockito.exceptions.base.MockitoException: 
Cannot instantiate @InjectMocks field named 'mainClass' of type 'class com.main.MainClass'.
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : null

Caused by: java.lang.NullPointerException
This null pointer exception is thrown from a the constructor of the BaseClass when it tries to initialize another class.
v1shnu
  • 2,211
  • 8
  • 39
  • 68
  • Show the constructor of BaseClass. There you get an error – Jens Jul 20 '16 at 08:34
  • Why are you stubbing MainClass? Isn't that the class you are testing? – Adriaan Koster Jul 20 '16 at 08:44
  • @Jens The base class constructor take someClass passed from mainClass as an argument. It also uses this someClass and uses it to initialze few other classes which also has a constructor which uses someClass. – v1shnu Jul 20 '16 at 09:24
  • @AdriaanKoster can you please explain ? – v1shnu Jul 20 '16 at 09:27
  • You should not do anything like `PowerMockito.whenNew(MainClass.class).withArguments(Mockito.any(SomeClass.class)).thenReturn(mainClass);)`. You should be testing against a normal instance of MainClass without any stubbing behavior. – Adriaan Koster Jul 21 '16 at 09:50

3 Answers3

1

This question explains the difference between @Mock and @InjectMocks:

@Mock creates a mock. @InjectMocks creates an instance of the class and injects the mocks that are created with the @Mock (or @Spy) annotations into this instance.

MainClass constructor expects a SomeClass parameter but there isn't any mock for that.

Your code should be something like:

@RunWith(PowerMockRunner.class)
public class TestClass{

    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    SomeClass mock1;

    @InjectMocks
    MainClass mainClass;

    @Before
    public void setUp() throws Exception{
    ...
Community
  • 1
  • 1
Liviu Stirb
  • 5,876
  • 3
  • 35
  • 40
  • I did this. But still the code goes into the BaseClass. I get a null pointer again from the BaseClass when it tries to init. – v1shnu Jul 20 '16 at 09:22
  • @ViChU I expect this is a different and it has something to do with the way base class uses that mock. probably is doing something with the return object from a method from SomeClass. try using @Mock(answer = Answers.RETURNS_DEEP_STUBS) – Liviu Stirb Jul 20 '16 at 09:29
  • I tried this. It still throws a null from the BaseClass. When MainClass const calls super(someClass), it calls BaseClass const with someClass. Inside the contructor, there are a few objects created. Some access someClass object while others use someClass in their constructor. – v1shnu Jul 20 '16 at 09:34
  • Unfortunately I can't share the source code. Anyways I will try other methods and get back. – v1shnu Jul 20 '16 at 09:44
  • Do you really need to invoke `initMocks` if you annotate the test class with `@RunWith(PowerMockRunner.class)`? – Adriaan Koster Jul 21 '16 at 09:55
  • @no; probably not; I keep it as original; updated now – Liviu Stirb Jul 21 '16 at 09:56
0

Quoting this answer, which is quoting the @InjectMocks documentation:

Constructor injection; the biggest constructor is chosen, then arguments are resolved with mocks declared in the test only. Note: If arguments can not be found, then null is passed.

So, presumably, declare a field of type SomeClass, and annotate it @Mock.

Community
  • 1
  • 1
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
0

If you can't show us the actual code it is very hard to guess what exactly is happening. But it looks like your mock SomeClass needs some stubbed behavior to satisfy the BaseClass constructor.

For example:

// the instance of MainClass you run your tests against
private MainClass instance;

@Mock
private SomeClass someClass;
@Mock
private SomethingElse somethingElse;

@Before
public void setUp() {
    when(someClass.doSomething()).thenReturn(somethingElse);
    instance = new MainClass(someClass);
}

@Test
public void test() {
    // SETUP
    when(somethingElse.doWeirdStuff()).thenThrow(new WeirdException());

    // CALL
    instance.performTapDance();

    // VERIFY
    assertTrue(instance.isWeird());
}
Adriaan Koster
  • 15,870
  • 5
  • 45
  • 60