使用“真实数据”设置测试系统

时间:2012-10-19 12:28:00

标签: java testing junit junit4

所以现在我正在使用JUnit 4,在@BeforeClass方法中,我设置了重置用户模式或准备样本数据所需的一切。 现在,并不是我不喜欢这种方法,但我发现它非常令人沮丧,原因如下:

  • 我正在使用参数化注释来使用不同的输入数据运行相同的测试。参数化不适用于@BeforeClass,因为@BeforeClass适用于静态方法。

这意味着如果我想保留@BeforeClass逻辑,我必须复制测试。我不能使用@After和@Before,因为这些将在每次测试后发生,这将是一个开销。

我想我可以重构这个单元测试,因为我会编写一个处理测试的抽象类,以及我想要尝试的每个组参数的子类,这样我就可以只编写一次测试代码。

我希望您可以使用以下起点建议更清晰的选项:使用@Parameterized,每个参数组只需运行一次“数据库”方法。

编辑:

这是我没有BeforeClass

的班级的例子
RunWith(LabelledParameterized.class)
public class TestCreateCampaign extends AbstractTestSubscriberCampaign {

    public TestCreateCampaign(String label, String apiKey, String userKey,
            int customerId) {
        super(label, apiKey, userKey, customerId);
    }

    @Before
    public void setUp() throws Exception {
        super.setUp();
    }

    @After
    public void tearDown() throws Exception {
        super.tearDown();
    }

    @Parameters
    public static Collection<Object[]> generatedData() {
        return DataProvider.generatedCorrectSubscriberData();
    }

    @Test
    public void testCreateEmailCampaignBothTriggered() {

        // TEST

    }

    @Test
    public void testCreateTextCampaignTriggered() {

        // TEST

    }

    @Test
    public void testCreateTextCampaignTest() {

        // TEST

    }

    // Other Tests

}

3 个答案:

答案 0 :(得分:0)

如何从参数化测试类的构造函数中调用setup方法?

编辑:

好的,我不知道任何自动执行此操作的内容,但我认为您可以编写Rule代码来执行此操作。您可以从extend Rule开始实现ExternalResource。这是我认为它会做的。

  1. 构造函数将获取测试类的实例和ExternalResource实例。
  2. 在构造函数中,它会找到包含@Test注释的方法列表以获取计数。它会将迭代计数设置为0。
  3. before方法中,它会增加迭代次数,如果在增量之后为1(或之前为0),它将在传递的before上调用ExternalResource方法。
  4. after方法中,它会检查迭代次数是否等于测试次数,如果是,则调用传递的after上的ExternalResource方法。
  5. 您可能需要使用不同的回调类/接口和ExternalResource,因为beforeafter方法是protected。如果你真的想变得很酷,你可以在规则中定义自己的BeforeParametersAfterParameter注释,它会在传递的实例中查找这些方法。

    如果您开发此内容,请将其发布或提交给JUnit以便收录。

    这是我提出的,不像我想的那样好:

    @RunWith(Parameterized.class)
    public class TestExample {
    
    private interface BeforeAfter {
        void before();
    
        void after();
    }
    
    public static class Resource extends ExternalResource {
    
        private final int count;
        private final BeforeAfter ba;
        private int iteration = 0;
    
        Resource(Object instance, BeforeAfter ba) {
            int localCount = 0;
            for (Method method : instance.getClass().getMethods()) {
                if (method.getAnnotation(Test.class) != null) {
                    localCount++;
                }
            }
            this.count = localCount;
            this.ba = ba;
        }
    
        @Override
        protected void before() throws Throwable {
            if (iteration == 0) {
                ba.before();
            }
    
            iteration++;
        }
    
        @Override
        protected void after() {
            if (iteration == count) {
                ba.after();
    
                iteration = 0;
            }
        }
    }
    
    @Parameters
    public static Iterable<Object[]> data() {
        return Arrays.asList(new Object[][] { { 3, 0 }, { 4, 1 } });
    }
    
    @Rule
    public static Resource resource = new Resource(new TestExample(0, 0), new BeforeAfter() {
    
        @Override
        public void before() {
            System.out.println("setup");
        }
    
        @Override
        public void after() {
            System.out.println("cleanup");
    
        }
    });
    
    private int fInput;
    private int fExpected;
    
    public TestExample(int input, int expected) {
    
        // System.out.println("Constructor invoked" + fInput);
        fInput = input;
        fExpected = expected;
    }
    
    @Test
    public void test1() {
        System.out.println("test1 fInput=" + fInput);
    }
    
    @Test
    public void test2() {
        System.out.println("test2 fInput=" + fInput);
    }
    }
    

    导致:

    setup
    test1 fInput=3
    test2 fInput=3
    cleanup
    setup
    test1 fInput=4
    test2 fInput=4
    cleanup
    

答案 1 :(得分:0)

这取决于您要如何设置类,但您可以使用ClassRule。这与TestRule完成相同的工作,但它为每个类运行一次,而不是每次测试。这可以与Parameterized和TestRule结合使用,例如:

@RunWith(Parameterized.class)
public class TestCreateCampaign {
  @ClassRule
  public static ExternalResource beforeAfterClass = new ExternalResource() {

    @Override
    protected void before() throws Throwable {
      System.out.println("before each class");
    }

    @Override
    protected void after() {
      System.out.println("after each class");
    }
  };

  @Rule
  public ExternalResource beforeAfter = new ExternalResource() {
    @Override
    protected void before() throws Throwable {
      System.out.println("before each test");
    }

    @Override
    protected void after() {
      System.out.println("after each test");
    }
  };

  @Parameters(name = "{index}: fib({0})={1}")
  public static Iterable<Object[]> data() {
    return Arrays.asList(new Object[][] { { 3, 0 }, { 4, 1 } });
  }

  private int fInput;
  private int fExpected;

  public TestCreateCampaign(int input, int expected) {
    fInput = input;
    fExpected = expected;
  }

  @Test
  public void test1() {
    System.out.println("test1 fInput=" + fInput);
  }
}

这会产生以下输出:

before each class
before each test
test1 3
after each test
before each test
test1 4
after each test
after each class

这似乎是你正在寻找的。为了减少重复量,你当然可以在一个单独的java类中定义beforeAfterClass和beforeAfter。

这些在JUnit 4.9 +。

中可用

答案 2 :(得分:0)

有关每次测试运行仅初始化测试数据的方法,请参阅How to load DBUnit test data once per case with Spring Test