JUnit 4:嵌套测试

时间:2018-11-11 08:00:04

标签: java testing junit

我有一个要测试的数据转换类。给出了接口ITransformer。该类如下所示:

public class MyDataTransformer implements ITranformer {

    public MyDataTransformer() {}

    @Override
    public void init(String[] args) throws Exception {
        if (args.length == 0)
            throw (new Exception("bad input"));

        // do initialization
    }

    @Override
    public byte[] transform(byte[] input) {
        try {
            return transform_internal(input);
        } catch (Exception e) {
            return null;
        }
    }

    private static byte[] transform_internal(byte[] input) throws Exception {
        // do something
    }
}

这是我目前拥有的测试班:

public class TransformerTest {

    private MyDataTransformer transformer;

    @BeforeClass
    public void setUp() {
        String[] args = new String[4];
        // set args

        try {
            transformer = new MyDataTransformer();
            transformer.init(args);
        } catch (Exception e) {
            fail(e.getMessage());
        }
    }

    @Test
    public void testTransform() {
        byte[] input = read_input(); // omitted here for brevity

        byte[] output = transformer.transform(input);
        // this only tests if "valid" data was returned, but does not look into it
        assertNotNull("Transformation failed", output);

        // these 2 test some properties of the result data and should be separate tests
        assertTrue("transformation step 1 failed", test_transformation_1(output);
        assertTrue("transformation step 2 failed", test_transformation_2(output);
    } 
}

在测试方面,我遇到两件事。

首先,如何仅一次正确测试init方法?从语义上讲,init属于@BeforeClass块,但此块不是适当的测试。

第二,如何将test_transformation_1分离到自己的测试中,但要确保仅在testTransform成功完成后才能运行此测试(否则,对无效输入运行此测试是不明智的)。

在我看来,嵌套测试可以解决这两个问题,因此是问题的标题。但是,此示例可能会增加,我可能会添加不需要嵌套的独立测试,并且我想使其尽可能简单。

2 个答案:

答案 0 :(得分:0)

是什么让您觉得它“明显地”属于BeforeClass?从语义上来说,测试属于您所测试类的任何方法的预期行为...属于 test 方法。不要进入准备休息的方法。

一个有意义的初始化方法将需要接收每个测试用例的设置数据。因此,如果有的话,您将有一个 MyDataTransformer underTest 字段,该字段将通过@Before方法初始化。使用以后可以进行正确测试的参数。

测试init方法的行为是否符合预期并抛出该异常属于一个独特的名为@Test的方法。

除此之外,您可以强制Junit以给定的顺序执行测试用例(例如按字典顺序排序)。那不是很好的做法,但是有时候可以解决此类订购问题。

答案 1 :(得分:0)

称为init的函数之间没有链接,并且在单元测试中应该只运行一次,也可以在每个函数之前运行。

使测试依赖另一个测试是一种不好的做法,您必须将其测试上下文分开,否则会导致噩梦,如果第二个测试依赖另一个测试,则可能会失败,因为第一个测试已更改了另一个测试。它们之间共享状态。因此,您正在缓慢寻找回归的根本原因,即使您决定按字母顺序排列测试,如果您在同一项目中工作的人很多,而又有人以不同的方式命名他的测试,您会发现...也很糟糕。

嵌套类的目的是按域对测试进行分组,从而提高测试的质量和可维护性。我在您的设计中看到的只是一个领域。

  

题外话:   出于可维护性的考虑,抛出通用的Exception类是一种专门的做法,这是不好的做法。   我也看到代码中有异味,为什么您为什么要在catch中返回,通常,您必须记录异常或将其抛出,并且返回必须在外部,另外,为了将来避免麻烦,请返回一个空数组为空。