#java #unit-testing #mockito
Вопрос:
Я пытаюсь протестировать следующий класс
public class MyClass {
protected OtherClass other;
public MyClass(String arg) {
this.other = new OtherClass(arg);
}
public void doSomething() {
String response = other.sendRequest(); // mock this call
// ...
}
}
Я хочу проверить doSomething()
, и для этого мне нужно издеваться над вызовом sendRequest()
. Для этого я попробовал следующее, что не сработало:
@Test
public void doSomethingTest() {
MyClass myClass = new MyClass("test");
when(myClass.other.sendRequest()).thenReturn("response");
myClass.doSomething();
}
Реальный sendRequest()
все еще вызывается вместо того, чтобы возвращать поддельный ответ.
Как я могу издеваться над вызовом sendRequest()
с помощью Mockito?
Комментарии:
1. Вам нужно ввести объект OtherClass в MyClass (например, с помощью конструктора). Если вы создадите экземпляр объекта OtherClass в классе MyClass, то на самом деле невозможно издеваться над ним
2. Классический случай внедрения зависимостей. В исходном коде объект, используемый для вызова sendRequest, создается снаружи. Ваш тест никогда не сможет получить доступ к этому объекту. Вы создаете макет, но этот макет объекта никогда не вызывается, потому что класс Myclass даже не принимает макет. Но если вы отправите созданный объект pbject в Myclass, то в вашем тесте вы можете заменить другой объект класса объектом, созданным в вашем тесте. Вот как инъекция зависимостей помогает в тестах. Это позволяет u заменить объект, который будет использоваться в классе.
Ответ №1:
Если вы создаете экземпляр OtherClass
объекта в MyClass
классе, то на самом деле невозможно издеваться над ним, вам нужно создать его вне MyClass
, а затем внедрить в MyClass
него (например, через его конструктор).
Тогда все, что вам нужно сделать в своем тесте, — это имитировать вызов макетного OtherClass
объекта. И используйте его для создания экземпляра MyClass
объекта
Измените MyClasss, чтобы быть
public class MyClass {
protected OtherClass other;
public MyClass(OtherClass otherClass) {
this.other = otherClass;
}
public void doSomething() {
String response = other.sendRequest();
}
}
и ваш код изменится с
MyClass myClass = new MyClass("s");
Для
OtherClass other = new OtherClass("s");
MyClass myClass = new MyClass(other);
И теперь вы можете написать этот тест:
@Test
public void doSomethingTest() {
OtherClass other = mock(OtherClass.class);
when(other.sendRequest()).thenReturn("response");
MyClass myClass = new MyClass(other);
myClass.doSomething();
// .. test assertions
}
Комментарии:
1. Возможно, вам не придется менять свой класс MyClass. Вы могли бы наследовать от него в своем тесте по sth. например, MyTestClass расширяет MyClass{ MyTestClass(строка s){другое =макет(OtherClass.class); когда(other.sendRequest()).Затем вернитесь(«ответ»); } } и затем вы протестируете с помощью MyClass MyClass = новый MyTestClass(«s»);
2. @juwil Это звучит плохо для меня, это не то, для чего предназначено наследование. Другим способом может быть наличие защищенного конструктора (следовательно, доступного из теста), который принимает объект OtherClass