Макет вложенного класса с параметрами конструктора и тестирование методов

#java #junit #mockito #powermock

#java #junit #мокито #powermock

Вопрос:

Я пытаюсь создать макет класса, который имеет вложенный класс. Этот вложенный класс был с аргументом конструктора. Когда я пытаюсь протестировать с помощью mockito вместо того, чтобы издеваться, выполняется фактический метод.

Я выполнил @InjectMocks для внешнего класса и @Mock для внутреннего класса.

 //Actual Class to test using Mockito.

public class ClassA {

public void initMethod(String s1, String s2, String s3, String s4) throws Exception {

    ClassB objB = null;
    if (objB == null amp;amp; s3 != null amp;amp; s4 != null amp;amp; s2 != null) {

        SampleUtil.KeyStorePasswordPair pair = SampleUtil.getKeyStorePasswordPair(s3, s4);


        objB = new ClassB(s1, s2, pair.keyStore, pair.keyPassword);

        try {
            objB.meth1();  //Note: meth1 and meth2 are void methods.  
            objB.meth2();  // These two methods only to be accessed. something like doNothing

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
}
 

Который я попытался, как обычно, вызвать с помощью класса @Mock, но фактический метод meth1() получает доступ.

 //Somthing which I tried 
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {


@InjectMocks
ClassA classA;

@Mock
ClassB classB;

@Before
public void initMocks() {
    MockitoAnnotations.initMocks(this);
}

@Test
public void testInitClient() throws Exception {
    // Setup

    // Run the test
    classA.initMethod("Lorem", "Ipsum", "TestStr1", "TestStr2");

    doNothing().when(classB).meth1(); // This is the line need to be mocked. But instead calling the actual method and executing
    // Verify the results
} 
 

Внутренний метод ClassB должен быть высмеян вместо доступа к реальному методу.

Как новичок в mockito, я пытаюсь прояснить это. Но запутался в нескольких моментах, таких как доступ к методу void, ПОЭТОМУ не могу использовать when then. Доступ к конструктору с параметром и т. Д.,

Ответ №1:

Я не думаю, что это возможно без какой-либо инъекции зависимостей.

Здесь я изменил ваш код, чтобы он вел себя так, как вы хотели.

 public class ClassA {
    // Needed so that it can be replaced with setter
    private ClassB objB;

    // Extract the generation of ClassB so that it can be prevented
    public void generateClassB(String s1, String s2) {
        this.objB = new ClassB(s1, s2);
    }

    public void initMethod(String s1, String s2, String s3, String s4) {

        objB = null;
        if (s3 != null amp;amp; s4 != null amp;amp; s2 != null) {

            SampleUtil.KeyStorePasswordPair pair = SampleUtil.getKeyStorePasswordPair(s3, s4);

            generateClassB(s1, s2);

            try {
                objB.meth1();  //Note: meth1 and meth2 are void methods.
                objB.meth2();  // These two methods only to be accessed. something like doNothing

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void setClassB(ClassB classB) {
        this.objB = classB;
    }
}
 

Это реализация ClassB, которую я использовал для проверки результатов.

 public class ClassB {
    private String s1;
    private String s2;

    public ClassB(String s1, String s2) {
        this.s1 = s1;
        this.s2 = s2;
    }

    public void meth1() {
        System.out.println(s1);
    }

    public void meth2() {
        System.out.println(s2);
    }
}
 

И тестовый файл

 @RunWith(MockitoJUnitRunner.class)
public class DemoApplicationTests {
    private ClassA classA;
    private ClassB classB;

    @Test
    public void testInitClient() {
        classA = Mockito.spy(ClassA.class);
        classB = Mockito.spy(new ClassB("a", "b"));

        Mockito.doNothing()
                .when(classB)
                .meth1();

        // This will replace the ClassA#generateClassB method call with the setter
        Mockito.doAnswer(args -> {
            classA.setClassB(classB);
            return null;
        }).when(classA).generateClassB(Mockito.any(), Mockito.any());
        classA.initMethod("a", "b", "c", "d");
    }
}
 

Альтернативным и гораздо более чистым решением было бы передать экземпляр ClassB в ClassA#initMethod .