Насмешка над конструктором, который дает ссылку на базовый класс, используя 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 для того, чтобы вернуть только что созданный макет.

Для справки: я играл со шпионами некоторое время; но они не помогают здесь; и они тоже не обязательны!

Другие вопросы по тегам