1

I Have no access to MyClass2 code and can't change it. How do i mock/instantiate MyClass2 myClass2?

Classes and code test:

@RunWith(JUnit4.class)//can't change thisone
public class MyTest
{
    @Autowired // or not, tried both ways
    MyClass testedInstance= new MyClass();
    @Test
    public void boot() throws Exception{
        testedInstance.boot();
        assertTrue(true);
    }
}

public class MyClass
{
    @Autowired 
    private MyClass2 myClass2;

    void boot()
    {
        myClass2.foo();//getting a null pointer here
    }
}
Alexander Petrov
  • 9,204
  • 31
  • 70
victor dabija
  • 505
  • 4
  • 11

3 Answers3

1

you can check the original answer

https://stackoverflow.com/a/71591567/5108695

But this is very common problem so I posted the answer here also

In my opinion, we are writing unit test cases and we should not initialize the spring context in order to test a piece of code.

So,

I used Mockito to mock the Autowired beans in my main target test class and injected those mock beans in my main test class Object

maybe sounds confusing, see the following example

Dependencies I used

    testImplementation("org.mockito:mockito-core:2.28.2")
    testImplementation("org.mockito:mockito-inline:2.13.0")
    testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
    testImplementation("org.mockito:mockito-junit-jupiter:4.0.0")

My main class is Maths and Calculator bean is autowired


class Maths{

   @Autowired Calculator cal;

   .........
   .........

   public void randomAddMethod(){
      cal.addTwoNumbers(1,2); // will return 3;
   }
}

Test class


@ExtendWith(MockitoExtension.class)

class MathsTest{

   @Mock(answer = Answers.RETURNS_DEEP_STUBS) Calculator cal;

   @InjectMocks Maths maths = new Maths();

   @Test testMethodToCheckCalObjectIsNotNull(){
      maths.randomAddMethod();
   }
}

Now cal will not be null in Maths class and will work as expected

Dupinder Singh
  • 7,175
  • 6
  • 37
  • 61
  • 1
    “we are writing unit test cases and we should not initialize the spring context in order to test a piece of code.” Can't agree more. – Chen Ni Nov 09 '22 at 03:09
0

First you need to annotate your test class with:

@RunWith( SpringJUnit4ClassRunner.class )

Then about MyClass:

@Autowired 
MyClass testedInstance;

you need to delete the = new MyClass(); because you are autowiring it.

Then since now you are injecting MyClass if there is available for injection instance of MyClass2 it will be injected in MyClass, if not it will not.

You need to configure your application context so that such bean MyClass2 exists,

Alexander Petrov
  • 9,204
  • 31
  • 70
0

Something that can bite is if you're using the implementation class for autowiring purposes in tests, but the operational code is using an interface instead and there is proxying. This can happen if, for example, you are using @PreAuthorize annotations from Spring Security, or pointcuts from Spring AOP. I'm not 100% sure if this happens with CGLIB proxies, but it definitely happens with JDK proxies.

You have to get exactly the correct bean or things will not work and you will get very strange ("impossible") null pointer exceptions due to the bean you're testing being in a half-configured state.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215