【问题标题】:How to test @Before method?如何测试@Before 方法?
【发布时间】:2016-09-19 04:42:29
【问题描述】:

JUnit 4.12

我目前正在为类方法编写测试。这是它的样子

public interface MyInterface{
    //method declaration
}

public class MyClass implements MyInterface{

    private int a;
    private in b;

    public MyClass(int a, int b){
        if(a <= b + 5)
            throw new IllegalArgumentException("Invalid arguments");
        this.a = a;
        this.b = b;
    }

    //methods
}

现在我想测试这个类:

public class MyClassTest{
    private static final int THRESHOLD = 1000;

    private MyClass mc;

    @Before
    public void init(){
        Random rnd = new Random();
        int a = rnd.nexInt(THRESHOLD), 
            b = rnd.nexInt(THRESHOLD);
        mc = new MyClass(a, b);
    }
}

但在这种情况下,init() 可能会抛出异常。所以我想测试保留不变量以及初始化一个对象以测试它的其他方法。

如何在 JUnit 中正确地做到这一点?

【问题讨论】:

  • 这个单元测试设计不正确。您通常会有 3 个具有固定值的测试用例 ab。一种测试a是否低于b+5,一种测试a等于b+5,最后一种测试a大于b+5。在这里使用Random 没有必要也没有帮助。
  • 为什么在@before 中这样做?如果你想测试异常,只需一个测试。
  • 在大多数情况下,在测试时使用随机/非确定性值是个坏主意。即使在应该以某种随机方式表现的类中,测试通常也被设计成它们的行为以某种方式变得可预测。
  • 我认为OP误解了@Before的功能。通常,在测试类中使用@Before 来初始化测试所需的一些值。此方法不调用任何测试,JUni-Runner 会为您完成。
  • 我同意@Psycho Punch。您要做的是测试已知的确定值以控制您的测试。如果您想测试异常,请在其中输入一个会引发异常的值,然后为该测试输入 @Test(expected = Exception.class)。请参阅以下链接以更好地了解如何测试异常。 stackoverflow.com/questions/15216438/junit-testing-exceptions

标签: java junit


【解决方案1】:

@Before 旨在初始化测试所需的任何内容。如果你想检查任何东西 - @Test 方法是显而易见的地方。

在您的情况下,我认为您应该创建几个单独的测试方法来显式传递有效和无效参数。这样,如果测试失败,您就会知道它发生的原因以及它是否没有失败——您可以确定逻辑是正确的。 如果你使用 random 你不能确定:也许测试的代码仍然是正确的或者随机值是合适的,你很幸运。

【讨论】:

    【解决方案2】:

    你需要两个测试类。

    第一个用于测试构造函数的行为。其次是测试方法的行为。 另外,我假设每个测试方法都需要@before 中定义的代码。

    所以我们有:

    public interface MyInterface{
        //method declaration
    }
    
    public class MyClass implements MyInterface{
    
    private int a;
    private in b;
    
    public MyClass(int a, int b){
        if (a <= b + 5) {
            throw new IllegalArgumentException("Invalid arguments");
        }
        this.a = a;
        this.b = b;
    }
    
    //methods
    }
    

    现在我们为构造函数创建测试

    public class MyClassConstructorTest{
    private static final int THRESHOLD = 1000;
    
    @Test
    public void allArgsConstructor_okValues_shouldCreateObjectOK(){
        // Given
        int a = 0; 
        int b = a - 5;
        // tested method
        new MyClass(a, b);
        // then no exception (test: ok)
    }
    
    
    @Test(expected = IllegalArgumentException.class)
    public void allArgsConstructor_aLesserBplus5_shouldThrowException(){
        // Given
        int a = 0; 
        int b = a; 
    
        // tested method
        new MyClass(a, b);
        // then fail constructor assertion
        // see expected annotation
    }
    
    // other tests for constructor you need?
    
    }
    

    然后你创建你的正常测试:

    public class MyClassTest{
    private static final int THRESHOLD = 1000;
    
    private MyClass mc;
    
    @Before
    public void init(){
        int a = 0; 
        int b = a+5;
        mc = new MyClass(a, b);
    }
    
    // normal test that use @before
    }
    

    PS:在 cmets 中也指出:永远不要在测试中使用 random。

    PS2:不确定是否可以,但您可能应该将问题重命名为:“如何测试构造函数方法”

    【讨论】:

      【解决方案3】:

      我认为您的问题始于使用随机数。如果您在单元测试中使用随机数,则必须确保您覆盖的范围适合一种情况且仅适合一种情况。在您的情况下,您实际上有三种情况:

      1. a
      2. a > b + 5 - 这是有效的情况。
      3. a = b + 5 - 这是另一个无效的情况

      您需要测试这三种情况,因此您需要为每种情况进行设置。您遇到的问题是您试图将所有案例合二为一。这种测试在单元测试中是非常不鼓励的,因为你引入了一个可变代码组件,正如你所说,需要测试。作为建议,制作 3 b 变量 b1 和 b2 和 b3

      说a是一个随机数。令 b1 = a - 5 - 1 和 b2 = a - 5 + 1 和 b3 = a - 5。然后为每种情况提供 3 种测试方法。我建议您使用覆盖率工具,例如 MoreUnit,因为它可以确保您更轻松地检测到实际需要测试的所有不同情况。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-08
        • 2010-12-05
        • 1970-01-01
        • 1970-01-01
        • 2011-12-20
        • 2013-02-27
        • 2012-05-11
        • 1970-01-01
        相关资源
        最近更新 更多