模拟一个抽象类并使用Mockito注释注入类?

时间:2016-01-25 13:55:58

标签: java unit-testing mockito powermock

是否可以使用Mockito注释模拟抽象类并使用模拟类注入它。我现在有以下情况:

@Mock private MockClassA mockClassA;
@Mock private MockClassB mockClassB;

@Mock(answer = Answers.CALLS_REAL_METHODS) private AbstractClassUnderTest abstractClassUnderTest;

@Before
public void init() {
    MockitoAnnotations.initMocks(this);
    Whitebox.setInternalState(abstractClassUnderTest, mockClassA);
    Whitebox.setInternalState(abstractClassUnderTest, mockClassB);
}

我想在AbstractClassUnderTest上使用像@InjectMocks这样的东西,但它不能与@Mock结合使用。目前的情况,来自Powermock的Whitebox,但我很好奇是否有可能只用注释来解决它。我无法找到任何解决方案或示例。

(我知道测试抽象类的反对意见,我个人而不是测试一个具体的实现,只是使用@InjectMocks。)

2 个答案:

答案 0 :(得分:6)

我不知道有什么方法可以解决这个问题,原因有一个:@InjectMocks适用于非模拟系统,而@Mock适用于模拟合作者,Mockito不适用于任何类在同一个测试中填写这两个角色。

请记住,您的@Mock(CALLS_REAL_METHODS)声明为inherently dangerous:您正在测试您的AbstractClassUnderTest,但您没有运行任何构造函数或初始化任何字段。我不认为你可以期望这种设计的测试是真实的或强大的,无论注释能为你做什么或不能做什么。 (就个人而言,我以前赞成抽象类的真正部分模拟作为工具箱中的工具"但是我想到他们认为他们离现实太远了很有用。)

如果我处于你的位置,我会为测试创建一个小的覆盖实现:

@RunWith(JUnit4.class) public class AbstractClassTest {
  /** Minimial AbstractClass implementation for testing. */
  public static class SimpleConcreteClass extends AbstractClass {
    public SimpleConcreteClass() { super("foo", "bar", 42); }
    @Override public void abstractMethod1() {}
    @Override public String abstractMethod2(int parameter) { return ""; }
  }

  @InjectMocks SimpleConcreteClass classUnderTest;
  @Mock mockClassA;
  @Mock mockClassB;
}

此时,您有一个简单且可预测的AbstractClass实现,如果您只想测试AbstractClass是否具有与之前相同的扩展API,则即使没有模拟框架也可以使用它。 (这是一个经常被忽视的抽象类测试。)你甚至可以提取它,因为它可能对其他测试有用:如果你想覆盖单个测试类的抽象行为,你可以创建一个匿名内部类只需一个方法覆盖,或者您可以设置classUnderTest = spy(classUnderTest);来设置Mockito代理和您想要的行为。

(请记住@InjectMocks和@Spy不能可靠地一起使用,如this GitHub issue及其链接的Google Code和邮件列表主题中所述。)

答案 1 :(得分:1)

在初始化之前,我发现了有关模拟字段的一些技巧。

@InjectMocks
private AbstractClass abstractClass;
@Mock 
private MockClass mockClass;

@Before
public void init() {
    abstractClass= mock(AbstractClass.class, Answers.CALLS_REAL_METHODS);
    MockitoAnnotations.initMocks(this);
}

也许会帮助某人。