简体   繁体   中英

Mocking a dependent class using Mockito in JAVA

I am quite new to Mockito. I apologise if my question sounds sill. I have a standalone JAVA application for which I have to write Unit test cases using JUnit and Mockito. The important thing is that I cannot change the code as it has been written by someone else and Integration testing has been completed. I have tried to search for similar questions, but couldnt find anything. Solutions suggested in somewhat similar questions, didnt work :(

I have attached the flow control diagram.I want to mock the dependent classes. For example when I am Unit testing 'Class 1 --> Method 1', I want to mock the output of 'Method 2 in Class 2' WITHOUT CALLING it. I have tried to use Mockito.when and Mockito.doReturn. Both call the dependent methods.

Can someone please suggest me some ideas to achieve this ?

控制流程

//Pseudocode of Class 1
public class Class1 {
    public boolean method1() {
        Class2 c2 = new Class2();
        boolean b1 = c2.method2();
    }
}

//Pseudocode of Class 2
public class Class2 {
    public boolean method2() {
        Class3 c3 = new Class3();
        boolean b2 = c3.method3();
    }
}

... Likewise same for Class 3, 4 and 5

What you're being asked to do is write unit tests for logic which was written by someone who knows absolutely nothing about writing code for test-ability. Probably a developer who's been writing code for a very long time, does things in an "old school" way and thinks he's way too important to write unit tests. Whoever wrote the logic you're testing needs to go back to school and learn some new tricks.

Anyway that doesn't help you, so you can still unit test this logic, it's just more of a pain. Mockito alone can't do it, you need "PowerMockito" which will let you mock the construction of Class2.

First things first you need to add 2 new test dependencies to your project "powermock-api-mockito"+"powermock-module-junit4".

A test class for you case would look something like:

@RunWith(PowerMockRunner.class)
@PrepareForTest(Class1.class)
public class Class1Test {
    private Class1 testSubject;

    @Mock 
    private Class2 class2;

    @Test
    public void testMethod1() throws Exception {
        testSubject.method1();
        verify(class2).method2();
    }

    @Before 
    public void setup() throws Exception {
        MockitoAnnotations.initMocks(this);
        PowerMockito.whenNew(Class2.class).withNoArguments().thenReturn(class2);
        testSubject = new Class1();
    }
}

So as you can see PowerMockito lets you mock out construction on new Class2 instances by using PowerMockito.whenNew() , this will only work if you've "prepared" Class1 using the annotation @PrepareForTest(Class1.class) otherwise Class1 can't be injected with the mock Class2 instance. Hopefully that points you in the right direction? On a side note, if you're a junior developer being asked to write unit tests for a more senior developer get out now, your development team is rotten!

Sometimes, code is not written to be testable.

Especially calling constructors inside methods or other constructors is a big issue for unit testing and mocking.

If you do not use factories or dependency inversion / dependency injection in any way, you will have a very hard time testing the code. This is one of the reasons why CDI is so popular.

Anyways, being asked to write Unit Tests after Integration Tests are already in place is kind of a bad smell. You should have written the unit tests first. If you follow Test Driven Development (TDD), you should have written your test even before you actually wrote your class. This way, it would be impossible to write classes that are hard to test.

But what to do on your already messed up situation?

  • I recommend to refactor your code. Instead of calling a constructor inside your methods, pass an instance into your method, or provide a field in the class in order to be able to mock it.
  • Reconsider the scope of your unit test. It should only test a single class. Everything else, all the dependencies should be mocked.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM