如何通过模拟编写单元测试,当你有零 arg:constructors

How to write unit test by mocking, when you have zero arg:constructors

我正在尝试使用 jmocks 和 junit 编写单元测试。 (我的项目使用核心 java- 无框架-)当依赖项在无参数构造函数中初始化时,我无法通过模拟外部依赖项为我的某些 classes 编写单元测试。

由于我无法提供实际代码,尝试通过示例解释场景

public interface Apple {

String variety();

}

实施。

public class MalgovaApple implements Apple {

  @Override
  public String variety() {
         return "Malgova";

  }

}

Class待测

public class VarietyChecker {
private Apple apple;

VarietyChecker(){
this.apple = new MalgovaApple();
// instead of new, a factory method is used in actual application
}

public String printAppleVariety(){
    String variety = apple.variety();
    if(variety.length() < 3){
       System.out.println("Donot use Code names- Use complete names");
       return "bad";
        }
       return "good";
}
}

使用 jmock 进行 Junit 测试

public class VarietyCheckerUnitTest{
Mockery context = new JUnit4Mockery();
@Before
public void setUp() throws Exception {
}

@After
public void tearDown() throws Exception {
}

@Test
public void test_VarietyChecker() throws Exception{

    final Apple mockapple = context.mock(Apple.class);

    VarietyChecker printer = new VarietyChecker();
    context.checking(new Expectations(){{
        oneOf(mockapple).variety();will(returnValue("as"));
    }});
    String varietyNameValid = printer.printAppleVariety();

    assertEquals("bad",varietyNameValid);


} }

此测试失败 - 模拟不起作用值 "as" 未注入,测试 class 使用 MalgovaApple 执行 ...

现在,如果我们将以下构造函数添加到 VarietyChecker 并使用它测试用例 - 它会给出预期的输出...

public VarietyChecker(Apple apple) {
    super();
    this.apple = apple;
}

并在单元测试中创建测试 class 对象 VarietyChecker 打印机 = new VarietyChecker(mockapple);

仅仅为了测试目的而公开一个新的构造函数不是一个好主意。毕竟都说不能单独改动测试代码,不止于此,恐怕我们已经写了"some"(数量)代码了...

我是否遗漏了 junit 或 jmock 中的某些东西,即使在没有参数的构造函数的情况下也可以使模拟工作。或者这是简单的 junit 和 jmocks 的限制,我应该迁移到像 Jmockit /PowerMock

这样强大的东西吗

你应该考虑两个选择。

  1. 按照您的描述使用构造函数参数。

    在这种情况下,您不是 "exposing a new constructor just for the purpose of testing"。通过允许调用者使用不同的工厂实现,您使 class 更加灵活。

  2. 不要嘲笑它。

    在这种情况下,您声明使用不同的工厂是没有意义的。有时这没关系。不过,到那时,问题就变了。而不是 "How do I mock this?" 你现在的问题是 "What am I gaining from writing this test?" 你可能不会得到很多东西,而且编写测试可能根本没有多大意义。

    如果您不模拟它并确定单元测试仍然值得,那么您应该对代码的其他方面进行断言。结束状态或一些输出。在这种情况下,工厂调用成为不适合模拟的实现细节。

    重要的是不要陷入 "unit test everything" 心态。这是测试引起的设计损坏的秘诀。根据具体情况评估您的测试,确定它们是否为您提供任何实际价值。不编写单元测试是一个有效的选择,有时甚至是合适的,即使这是您极力避免的选择。

在这种情况下,只有您才能确定哪一个最有意义。从我们正在谈论的这是一个工厂对象这一事实来看,我可能倾向于前者。