Getting NullPointerException while calling nested method of Service class using mockito

问题: I am writing JUnit test cases for my Service classes. I have created dummy data to understand my scenario. @Service MainClass { @Autowired C c; public void so...

问题:

I am writing JUnit test cases for my Service classes. I have created dummy data to understand my scenario.

@Service
MainClass {
    @Autowired
    C c;
    public void someServiceMethod(){
        ResultClass someResult = c.getResult(string,string, int, int, List<String>,boolean);
    }
}

@Service
public class C {
    @Autowired
    SomeRepository someRepository;
    public ResultClass getResult(string,string, int, int, List<String>,boolean){
        ABC returnSomeClassObject = someRepository.getSomeData(String,int,int);
    }
}

@Test
MainClassTest {
    @MockBean
    SomeRepository someRepository;
    when(someRepository.getSomeData(anyString(),anyInt(),anyInt())).thenReturn(SomeRepository);

    //calling MainClass method
    MainClass.someServiceMethod();
}

Class C's getSomeData() method returning ABC class object which is NULL and latter setting into another same class type object. After setting value I am getting NULLPointerException as ABC is NULL. Anybody have any idea where I am going wrong?


回答1:

You are not returning expected object while writing mock statement

    @Service
public class C {
    @Autowired
    SomeRepository someRepository;
    public ResultClass getResult(string,string, int, int, List<String>,boolean){
        ABC returnSomeClassObject = someRepository.getSomeData(String,int,int);

        //Your return type should be ResultClass 
        // Where your return statement
        // What is ABC?
    }
}

@Test
MainClassTest {
    @MockBean
    SomeRepository someRepository;
    when(someRepository.getSomeData(anyString(),anyInt(),anyInt())).thenReturn(SomeRepository);
    // Why are you returning SomeRepository, This Should return object of ABC

@MockBean 
ABC mockResultClass
when(someRepository.getSomeData(anyString(),anyInt(),anyInt())).thenReturn(mockResultClass);

    //calling MainClass method
    MainClass.someServiceMethod();
}

回答2:

You are calling MainClass.someServiceMethod() which in turn calls getResult of class C. You should be mocking class C and using when-thenReturn on getResult() of C class if your intention is to test someServiceMethod() of Main class. Autowired will not work here since this is a Unit test and hence the instance of C c in Main class will be null. Something like below:

@MockBean
C c;
when(c.getResult(anyString(), anyString(),anyInt(),anyInt(), any(List.class), anyBoolean()).thenReturn(someResult);

c.getResult(string,string, int, int, List<String>,boolean);

回答3:

So, first of all, we need to be clear on what exactly you are unit testing. If you are trying to unit test someServiceMethod inside of MainClass, then that means you should NOT be also testing the functionality of someRepository. The idea is that each unit test should only be testing just that, a unit of code. So, to do that we need to use stubs as stand-ins for what would actually happen when you call methods owned by other classes. Then, we would write a differrent unit test just for someRepository.getSomeData() to confirm that it is also working as intended. In this manner, when get an error later down the line we will know exactly where we are encountering an issue.

Another issue I see is there is an apparent mismatch of return types for getResult() in C. The method says it returns a ResultClass, but when you call getSomeData you are expecting an ABC object. Either you left out the details where you convert the object back to a ResultClass, or that is a mistake. I'm going to assume the former unless you say otherwise.

With that in mind, let's write our test. Here's how I would write the test:

@RunWith(SpringRunner.class)
public class MainClassTest {

    @Mock
    C c;

    @InjectMocks
    MainClass mainClass;

    @Test
    public void testSomeServiceMethod {

        ResultClass resultClass = new ResultClass(); //relevant constructor details here, mockbean, etc. you get the idea

        //set any desired data for resultClass here

        Mockito.when(c.getResult(anyString(), anyString(), 
            anyInt(), anyInt(), any(List.class), anyBoolean()))
            .thenReturn(resultClass);

        ResultClass newResult = mainClass.someServiceMethod();

        //relevant test assertions here
    }
}

As you can see, we are creating a ResultClass in the test, and telling Mockito to return that when getResult is called instead of what you would normally expect it to return. While the functionality may seem limited now, this is preferred as we only testing the MainClass and not the rest of our method calls.

In addition to this, we can (and should) write tests for getResult in C, and getSomeData in SomeRepository. I will leave it to you to write those tests.

EDIT: accidentally posted a bit early, fixing now.

  • 发表于 2018-12-29 20:01
  • 阅读 ( 196 )
  • 分类:网络文章

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除