如何对构造函数进行单元测试

ICR*_*ICR 36 java unit-testing

我有一个课我正在添加单元测试.该类有几个构造函数,它们采用不同的类型并将它们转换为规范形式,然后可以将其转换为其他类型.

public class Money {
    public Money(long l) {
        this.value = l;
    }

    public Money(String s) {
        this.value = toLong(s);
    }

    public long getLong() {
        return this.value;
    }

    public String getString() {
        return toString(this.value);
    }
}
Run Code Online (Sandbox Code Playgroud)

实际上,它接受并转换为其他几种类型.

我试图找出测试这些构造函数最合适的方法.

应该有每个构造函数和输出类型的测试:

@Test
public void longConstructor_getLong_MatchesValuePassedToConstructor() {
    final long value = 1.00l;

    Money m = new Money(value);
    long result = m.getLong();

    assertEquals(value, result);
}
Run Code Online (Sandbox Code Playgroud)

这导致了许多不同的测试.如你所见,我很难为它们命名.

应该有多个断言:

@Test
public void longConstructor_outputsMatchValuePassedToConstructor() {
    final long longValue = 1.00l;
    final String stringResult = "1.00";

    Money m = new Money(longValue);

    assertEquals(longValue, m.getLong());
    assertEquals(stringResult, m.getString());
}
Run Code Online (Sandbox Code Playgroud)

这有多个断言,让我感到不舒服.它还测试getString(和代理toString),但没有在测试名称中说明.命名这些更难.

通过关注构造函数,我是否会完全错误.我应该只测试转换方法吗?但接下来的测试将错过该toLong方法.

@Test
public void getString_MatchesValuePassedToConstructor() {
    final long value = 1.00;
    final String expectedResult = "1.00";

    Money m = new Money(value);
    String result = m.getLong();
    assertEquals(expectedResult, result);
}
Run Code Online (Sandbox Code Playgroud)

这是一个遗留类,我无法更改原始类.

Jon*_*eet 16

看起来你有一个规范的方法来获取"原始"值(toLong在这种情况下) - 所以只需测试所有构造函数在获取值时是否正确.然后,您可以getString()基于单个构造函数测试其他方法(例如),因为您知道一旦各种构造函数完成,它们都将对象保持在相同的状态.

这假设有点白盒测试 - 即你知道toLong实际上是内部状态的简单反映,所以可以在测试中测试+一个构造函数.

  • @ICR:我发现在网上测试中有一些有点教条散文的*.我宁愿拥有大量务实但不完美的测试,而不仅仅是一个完美的测试实际上并没有多少帮助:) (5认同)

And*_*s_D 14

构造函数测试的预期结果是:已创建实例

遵循这个想法,您可以将构造函数测试中的工作限制为纯实例化:

@Test public void testMoneyString() {
    try {
      new Money("0");
      new Money("10.0");
      new Money("-10.0");
    } catch (Exception e) {
      fail(e.getMessage());
    }
}

@Test public void testMoneyStringIllegalValue() {
    try {
      new Money(null);
      fail("Exception was expected for null input");
    } catch (IllegalArgumentException e) {          
    }

    try {
      new Money("");
      fail("Exception was expected for empty input");
    } catch (IllegalArgumentException e) {          
    }

    try {
      new Money("abc");
      fail("Exception was expected for non-number input");
    } catch (IllegalArgumentException e) {          
    }

}
Run Code Online (Sandbox Code Playgroud)

验证转换是否有效的测试可以分配给getter.


ska*_*man 11

每个构造函数的测试似乎对我来说最合适.不要害怕为您的测试方法使用冗长,精细和冗长的名称,这使它们显而易见且具有描述性.

@Test
public void moneyConstructorThatTakesALong {
Run Code Online (Sandbox Code Playgroud)