简体   繁体   中英

Mockito: Override mock values in different methods

@RunWith(MockitoJUnitRunner.class)
public class Test {

     @Mock
     private SomeDependency<T> obj;

     @InjectMocks
     private SomeClass mainObj;

     @Test
     public void dependencyShouldBeNotNull() {
       //here I need one value of SomeDependency obj
       assertEquals(2, mainObj.method())
     }

     @Test
     public void dependencyShouldBeNull() {
       //here I need SomeDependency obj to be null
       assertEquals(1, mainObj.method())
     }

Main class:

class SomeClass {
      private SomeDependency<T> field;

      public int method() {
         if(field==null)
            return 1;
         else
            return 2;
      }
}

And my question: how to override value of mock according to different methods needs?

Edited In main SomeClass I have code like this:

if (obj != null) {
       //perform some actions
    }

The easiest way to do it is with 2 test classes instead of one because when it executes your test methods it is already too late since the mock has already been injected (unless you use refection which should be avoided).

The first test

@RunWith(MockitoJUnitRunner.class)
public class Test1 {
    @Mock
    private SomeDependency<T> obj;

    @InjectMocks
    private SomeClass mainObj;

    @Test
    public void dependencyShouldBeNotNull() {
        //here I need one value of SomeDependency obj
        assertEquals(2, mainObj.method());
    }
}

The second test

@RunWith(MockitoJUnitRunner.class)
public class Test2 {
    @InjectMocks
    private SomeClass mainObj;

    @Test
    public void dependencyShouldBeNull() {
        //here I need SomeDependency obj to be null
        assertEquals(1, mainObj.method());
    }
}

If you want to do it with only one test class, it is still possible but it is more like a hack because you want a conditional injection which is not a conventional approach, so you will need to inject the mocks programmatically with MockitoAnnotations.initMocks(obj) .

Instead of injecting the mocks directly into the test class, we need to rely on wrapper classes that will contain or not the field obj , if not present nothing will be injected so it will be null otherwise you will have a mock injected.

public class TestInjectMocks {

    /**
     * Small interface that will be implemented by the wrapper classes
     * only used to get the main class
     */
    public interface TestConfig {
        SomeClass getSomeClass();
    }

    @Test
    public void dependencyShouldBeNotNull() {
        // This class will allow to get an instance of SomeClass 
        // with the field injected
        TestConfig obj = new TestConfig() {
            @Mock
            private SomeDependency<T> obj;
            @InjectMocks
            private SomeClass mainObj;

            @Override
            public SomeClass getSomeClass() {
                return mainObj;
            }
        };
        MockitoAnnotations.initMocks(obj);
        SomeClass mainObj = obj.getSomeClass();
        //here I need one value of SomeDependency obj
        assertEquals(2, mainObj.method());
    }

    @Test
    public void dependencyShouldBeNull() {
        // This class will allow to get an instance of SomeClass 
        // without the field injected
        TestConfig obj = new TestConfig(){
            @InjectMocks
            private SomeClass mainObj;
            @Override
            public SomeClass getSomeClass() {
                return mainObj;
            }
        };
        MockitoAnnotations.initMocks(obj);
        SomeClass mainObj = obj.getSomeClass();
        //here I need SomeDependency obj to be null
        assertEquals(1, mainObj.method());
    }
}

NB: As we call MockitoAnnotations.initMocks(obj) explicitly the annotation @RunWith(MockitoJUnitRunner.class) is not needed anymore.

Based on what you've posted, I recommend using the 'Mockito.when()' method for the first method, then setting obj = null; as @Seelenvirtuose suggests. If that doesn't work, you might want to pass in a different Mocked out object which is initialized to null. See this example.

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