【问题标题】:Designing junit test cases - predefined steps for each test case设计 junit 测试用例 - 每个测试用例的预定义步骤
【发布时间】:2012-10-25 04:18:43
【问题描述】:

我有兴趣了解如何设计我的 junit 测试用例,以便它们更具可读性和可维护性。这就是问题所在 - 在我所有的 junit 测试用例中,我有一些预定义的步骤要执行,如下所示

public class MyTestClass {

private Service myService;

@Test
public void testCase1() {
    mockObjectX("A");
    mockObjectY(1);
    mockObjectZ("M", 1);

    myService.validate("value1", "value2");

}

@Test
public void testCase2() {
    mockObjectX("Q");
    mockObjectY(5);
    mockObjectZ("Z", 10);

    myService.validate("value3", "value4");

}


private void mockObjectZ(String value1, int value2) {
    //mock object Z
}

private void mockObjectY(Integer value) {
    //mock object Y
}

private void mockObjectX(String value) {
    //mock object X
}
}

问题是如果我要添加一个新的测试用例,我需要确保新的测试用例调用 mockObjectX()、mockObjectY()、mockObjectZ()。有没有更好的方法(更易于维护的方法)来设计我的测试用例,从而使添加新的测试用例变得更简单?

我认为 @Before 不能使用,因为 mock* 方法接受参数。

我能想到的一种方法是创建一个类,其中包含模拟对象 X、Y 和 Z 所需的每个参数值的方法

public class MyTestClass {

private Service myService;

@Test
public void testCase1() {
    mockObjects(new TestCase1());
    myService.validate("value1", "value2");

}

@Test
public void testCase2() {
    mockObjects(new TestCase2());
    myService.validate("value3", "value4");

}

private void mockObjects(ServiceObjectMocker serviceObjectMocker) {
    //mock object x, y and z by calling respective methods from serviceObjectMocker   
}  

private class ServiceObjectMocker {

    protected Object[] getValuesForObjectZ() {
        //pass default values
        return new Object[] {};     
    }

    protected Integer getValuesForObjectY() {
        //pass default values
        return 1;
    }

    protected String getValuesForObjectX() {
        //pass default values
        return "A";
    }

}

private class TestCase1 extends ServiceObjectMocker {
    @Override
    protected String getValuesForObjectX() {
        return "B";    
    }  
}

private class TestCase2 extends ServiceObjectMocker {
    @Override
    protected String getValuesForObjectX() {
        //pass different values
        return "Q";
    }

    @Override
    protected Integer getValuesForObjectY() {
        //pass default values
        return 10;
    }

}
}

这减少了数量。每个测试用例需要进行的方法调用次数。有更好的想法吗?

【问题讨论】:

    标签: java junit code-design


    【解决方案1】:

    如果你真的每次都在做同样的事情,只是数据不同,那么看看@Parameterized

    然后你可以有类似的东西(未经测试和未编译):

    @RunWith(Parameterized.class)
    public class MyTestClass {
      @Parameters
      public static List<Object[]> data() {
          return Arrays.asList(new Object[][] {
              { "A", 1, "M", 1, "value1", "value2" },
              { "Q", 5, "Z", 10, "value3", "value4" },
          });
      }
    
      private String xValue;
      private int yValue;
      private String zValueString;
      private int zValueInt;
      private String expected1;
      private String expected2;
    
      public MyTestClass(String xValue, int yValue, String zValueString, int zValueInt, String expected1, String expected2) {
        this.xValue = xValue;
        this.yValue = yValue;
        this.zValueString = zValueString;
        this.zValueInt = zValueInt;
        this.expected1 = expected1;
        this.expected2 = expected2;
      }
    
      @Test
      public void test() {
        mockObjectX(xValue);
        mockObjectY(yValue);
        mockObjectZ(zValueString, zValueInt);
    
        myService.validate(expected1, expected2);
      }
    }
    

    然后您只需定义一次测试。

    【讨论】:

    • 我仍然需要调用这三个方法——mockObjectX、mockObjectY 和mockObjectZ,这就是我想减少的,以使测试用例更易于维护。
    • 你说:“问题是如果我要添加一个新的测试用例,我需要确保新的测试用例调用 mockObjectX()、mockObjectY()、mockObjectZ()。有没有更好的设计我的测试用例的方式(一种更易于维护的方式),以便添加新的测试用例变得更简单?”。要将新的测试用例添加到 Parameterized,您需要在 data() 返回的列表中添加一行。这不是您要找的吗?
    • 我明白你的意思。我尝试将@Parmeterized 与 ServiceObjectMocker 一起使用,效果很好。谢谢!
    猜你喜欢
    • 2013-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多