Насмешка над конструктором, который дает ссылку на базовый класс, используя Powermockito в Java
Вот сценарий, у меня есть что-то подобное в одном из моих методов класса MyClass
public class MyClass{
public Object build(Map map) {
BaseClass cls;
if(SomeconditionTrue) {
cls = new ChildClass1(new ABC());
} else {
cls = new ChildClass2(new ABC());
}
cls.callMethod();
}
}
Для приведенного выше сценария я пишу тестовый пример с использованием PowerMockito, я хочу смоделировать этот вызов метода, cls.callMethod()
, Когда я пытаюсь издеваться, это вызывает фактический метод callMethod()
который терпит неудачу. Может ли кто-нибудь помочь мне посмеяться над вызовом метода? Пробовал использовать пару сценариев с использованием PowerMockito PowerMockito.stub и некоторых других опций, но всегда вызывал реальный метод. Причиной насмешек над этим методом является то, что он имеет разную логику, и он вызывает разные API, метод довольно сложный, поэтому нам нужно смоделировать этот метод.
1 ответ
Вы можете обратиться к Powermock для этого, но это не обязательно "лучший" ответ на такие проблемы.
По сути, тот факт, что вы вызываете в своем коде новое, вызывает у вас горе - вы создали труднодоступный для тестирования код. Вы можете посмотреть эти видео, чтобы понять, о чем я говорю.
Короче говоря: вместо того, чтобы обращаться к большому молотку Powermock, вы могли бы переработать свой код; использовать внедрение зависимости. Таким образом, вместо создания этих объектов сам по себе тестируемый класс может использовать какой-либо объект фабрики для предоставления необходимого ему объекта. И тогда вы можете использовать любую "обычную" среду для насмешек, такую как EasyMock или Mockito, чтобы создать версию этой фабрики.
Редактировать: Я думаю, что вы могли бы усложнить всю проблему. Видите ли, не имеет значения, существует ли базовый класс или два дочерних класса. Дело в том, что для каждого из ваших методов испытаний вы должны точно понимать, какой путь будет выбран. Вы либо хотите, чтобы child1 был создан, либо child. Таким образом, я создал упрощенное решение для вас:
package ghostcat.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
class Abc {}
abstract class Base {
void callMethod() {
System.out.println("Base::callMethod");
}
}
class ChildClass1 extends Base {
ChildClass1(Abc abc) {}
}
class MyClass {
public Object build() {
System.out.println("build1");
Base cls = new ChildClass1(new Abc());
System.out.println("build2");
cls.callMethod();
System.out.println("build3");
return null;
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(MyClass.class)
public class MockNewTest {
@Test
public void test() throws Exception {
ChildClass1 mock = Mockito.mock(ChildClass1.class);
PowerMockito.whenNew(ChildClass1.class).withArguments(Mockito.any(Abc.class)).thenReturn(mock);
new MyClass().build();
}
}
Печать:
build1
build2
build3
Итак, вы можете видеть - ничего в базе не называется; просто потому, что этот дочерний объект "полностью" осмеян.
Все дело в том, что тестируемый код просто требует один объект определенного типа; и вы заранее знаете, будет ли это child1 или child2. Так что вы просто создаете макет для этого класса; и используйте PowerMockito для того, чтобы вернуть только что созданный макет.
Для справки: я играл со шпионами некоторое время; но они не помогают здесь; и они тоже не обязательны!