【问题标题】:Why is this failing the unit test in Java? [closed]为什么这在 Java 中没有通过单元测试? [关闭]
【发布时间】:2016-08-15 16:27:25
【问题描述】:

我目前正在学习 Java。我对抛出异常进行了单元测试。我运行了单元测试但失败了。对此有何看法?

这是我的代码

public Card(int rank, int suit) throws SuitOutOfRangeException, RankOutOfRangeException {
    // TODO: Re-write this Constructor to throw exceptions
    try {
        if (suit > 4 || suit < 0) {
            throw new SuitOutOfRangeException();
        }
        this.suit = suit % 4;
    } catch (SuitOutOfRangeException ex) {
        System.out.println("Your input value for suit is out of the specified range");
    }

    try {
        if (rank > 12 || rank < 0) {
            throw new RankOutOfRangeException();
        }
        this.rank = rank % 13;
    } catch (RankOutOfRangeException ex) {

        System.out.println("Your input value for rank is out of the specified range");

    }
}

部分单元测试如下:

@Test
public void testConstructorShouldThrowRankOutOfRangeException() {
    boolean expected = true;
    boolean actual = false;
    try {
        Card c = new Card(100,1);
        actual = false;
    } catch (SuitOutOfRangeException ex) {
        actual = false;
    } catch (RankOutOfRangeException ex) {
        actual = true;
    }
    assertEquals(expected,actual);
}

解决办法是这样的

public Card(int rank, int suit ) throws SuitOutOfRangeException, RankOutOfRangeException {        
    if (rank <0 || rank > 12) throw new RankOutOfRangeException();
    if (suit <0 || suit >3) throw new SuitOutOfRangeException();
    this.suit = suit % 4;
    this.rank = rank % 13;
}

【问题讨论】:

  • 您的单元测试会清楚地说明失败的原因。请添加表明您的测试失败的错误消息。
  • 另请注意,这是一种可怕的测试方式,没有抛出异常......只需调用构造函数,如果抛出异常,测试无论如何都会失败。如果这些是检查的异常,我会让它们不检查(你需要特定的异常吗?)如果你不能这样做,只需让测试方法声明它可以抛出它们。
  • 另外,如果rank[0, 12] 范围内,而suit[0, 3] 范围内,你为什么要使用suit % 4rank % 13 而不仅仅是suitrank?

标签: java unit-testing


【解决方案1】:

让我们对您的代码提供一些更一般的反馈;还应该回答您不清楚的“我该怎么做”的问题。

首先,绝对抛出异常并在构造函数中捕获它是没有意义的。减少到:

public Card(int rank, int suit) { // please note: no checked exceptions!
  checkRank(rank);
  checkSuit(suit);
  this.suit = ... 

使用只检查和抛出的检查方法,例如

private void checkSuit(int suit) {
  if (suit < 0) throw new SuitOutOfRangeException("suit must not be negative: " + suit);
  ...

重点是:您希望将代码放入非常小的方法中。这种方法只有一个职责(例如:检查传入花色的有效范围)。并且:当您抛出异常时,您需要包含稍后了解失败所需的信息。

要测试这样的东西,你去:

@Test(expected=SuitOutOfRangeException.class)
public void testNegativeSuit() {
   new Card(1, -1);
}

就是这样。没有带有 printlns 和布尔值的 hokus pokus,仅此而已。所有这些都是浪费,没有添加任何有意义的东西;既不符合您的生产逻辑;也不是你的测试用例。请注意:也不需要你奇怪的断言。您期望抛出异常;没有别的了。这就是您要检查的内容!

谈论断言;当你确实需要断言时,了解一下 assertThat,比如

Card underTest = new Card(1, 2);
assertThat(underTest.getSuit(), is(2));

最后:考虑从 int 更改花色和等级的类型。让它们真正的类。当然,您可以从 int 输入构建 Rank 类;但也许,还有其他选择。事情是:编程是关于创建抽象。如果您不使用抽象......那么您必须一直处理那些低级细节。就像您的 Card 类必须知道有效的 int-ranks 应该是什么样子一样。如果你有Rank and Suit 类,那么Card 只会获得Rank and Suit;并且不必担心 int 范围!

【讨论】:

  • 很好的有用答案。 +1
【解决方案2】:

如果你捕获了一个异常,它不能被再次捕获,除非它再次被抛出到catch块中。

使用 Junit 你可以做这样的事情

例如

@Rule public ExpectedException thrown = ExpectedException.none();

@Test
public void throwsException() { 
    thrown.expect(NullPointerException.class);
    thrown.expectMessage("happened");
    throw new NullPointerException("What happened?");
}

http://junit.org/junit4/javadoc/4.12/org/junit/rules/ExpectedException.html

【讨论】:

  • 但你只是给出了那里的例子。不解释 thrown 有什么类型......我想这会让新手感到困惑而不是帮助他们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-22
  • 2018-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多