我应该在测试中重复实际课程中的代码吗?

时间:2015-04-12 09:58:47

标签: java unit-testing

我想测试一个特定方法产生预期结果,但为此我还需要操作测试中的输入。

class ToTest {
  public String produceResponse(String input) {
    // ....
    encryptedIds = encryptIds(input)
    output = doStuff(input, encryptedIds)
  }

  public encryptIds(input) {
    ....
  }
} 

在我的测试中,我需要检查produceResponse是否实际产生了预期的响应。 为了做到这一点,我必须加密输入中的ID。

我的问题是:我应该在测试中重写encryptIds(以便我在结果上有更多的控制器),还是应该从类本身调用encryptIds。

有没有更好的方法来解决这个问题?在我的测试中我不喜欢这样,我知道具体流程中会发生什么。

3 个答案:

答案 0 :(得分:3)

如果我理解正确,您希望使用已知的encryptedIds作为输入来测试produceResponse()

你可以在不重构代码的情况下做到这一点,但重构它可能是一个好主意,所以这就是我要解释的内容:

class ToTest {

    private IdEncryptor encryptor;

    public ToTest(IdEncryptor encryptor) {
        this.encryptor = encryptor;
    }

    public String produceResponse(String input) {
        String[] encryptedIds = encryptor.encryptIds(input);
        return doStuff(input, encryptedIds);
    }
} 

现在,您可以对IdEncryptor进行单元测试,以测试它是否根据String输入生成正确的加密ID。

要测试ToTest类,您可以模拟IdEncryptor,这样无论它接收什么输入,它都会产生您想要的encryptedIds。例如,使用mockito:

IdEncryptor mockEncryptor = mock(IdEncryptor.class);
when(mockEncryptor.encryptIds(any(String.class)).thenReturn(new String[] {"a", "b"});

ToTest toTest = new ToTest(mockEncryptor);
String response = toTest.produceResponse("input");
// expect that the response is what you expect given "a", "b" as input of doStuff()

答案 1 :(得分:0)

  1. 永远不要将任何生产代码复制到单元测试中,因为它会在某些时候过时。
  2. 如果两种方法都是公开的,则它们是公共API的一部分,所以:

    • 您应首先对encryptIds(String)方法
    • 的正确行为进行单元测试
    • 然后对produceResponse(String)方法进行单元测试,该方法将在内部使用已经过测试的encryptIds(String)方法
  3. 如果encryptIds(String)不属于公共API:

    • 然后是内部实现和辅助方法,它不是单元可测试的
    • produceResponse(String)负责加密作为副作用:
      • 如果您将包标记为私有(无修饰符)
      • ,您仍然可以测试它
      • 您也可以仅出于测试目的更改encryptIds(String)的实施

答案 2 :(得分:0)

加密id是你系统不可或缺的东西吗?目前这个类需要一些输入并产生一些输出,就你的测试而言,这是重要的,不多也不少。

不执行加密有什么影响?如果你的doStuff方法如果没有发生就会失败,那么它就是你的被测试阶段的内部细节,我根本不会让测试关心它。如果这是一个绝对必须执行的步骤,那么我将重构代码以验证它绝对已经发生,也许使用模拟作为@ jb-nizet回答。

至于在测试中复制生产代码的一般情况,正如@Crazyjavahacking所说,你不应该这样做,但我没有问题使用生产代码来测试 - 也许不是在一个单元水平,但绝对是我去的系统越高,例如当测试写入数据库时​​,我将使用读取代码来验证它是否正确发生,但也将进行独立测试以验证读取路径