繁体   English   中英

如何在 JUnit 中重用方法和测试?

[英]How to reuse method and test in JUnit?

我试图在 JUnit 测试中避免重复代码,但我有点卡住了。

这是我的第一个测试,对于第二个测试,它具有完全相同的方法但不同的服务(不同的输入)。 而不是TestCaseResourceTest1我有TestCaseResourceTest2 现在测试两者的正确方法是什么? 我想为测试编号 2 设置一个单独的文件,我应该如何避免重复代码? (例如,使用 beforeFileTest() 方法)

public class TestCaseResourceTest1 {

    @Mock
    private TestService testService;
    @Mock
    private AreaService areaService;

    private TestCaseService1 testCaseService1; // is changed in test2

    @Before
    public void before() throws Exception{
        testCaseService1 = mock(TestCaseService1.class); // is changed in test2
        MockitoAnnotations.initMocks(this);
        beforeFileTest();
    }

    private void beforeFileTest() throws Exception{
        doReturn(true).when(areaService).chechExists(any(String.class), eq(false));
    }

    @Test
    public void verifyFileExists() throws Exception{
        verifyOtherArea(testCaseService1); // is changed in test2
        doReturn(false).when(areaService).chechExists(any(String.class), eq(false));
    }
}

只是is changed in test2is changed in test2了注释的行是不同的。

Tnx

鉴于您的问题的摘录:

... 而不是 TestCaseResourceTest1 我有 TestCaseResourceTest2 ... 我想有一个单独的文件用于测试编号 2

...在测试用例之间共享代码的标准方法是:

  • 创建一个测试套件并将共享代码包含在测试套件中(通常在@BeforeClass@AfterClass方法中)。 这允许您 (1) 运行一次设置代码(每个套件调用); (2) 封装共享的设置/拆卸代码和 (3) 稍后轻松添加更多测试用例。 例如:

     @RunWith(Suite.class) @Suite.SuiteClasses({ TestCaseResourceTest1.class, TestCaseResourceTest2.class )} public class TestSuiteClass { @BeforeClass public void setup() { beforeFileTest(); } private void beforeFileTest() throws Exception { // ... } }
  • 创建一个父类TestCaseResourceTest1TestCaseResourceTest2的抽象类,并让这些测试用例调用父类中的共享代码(通常通过super()调用)。 通过这种方法,您可以在父类中声明默认共享代码,同时仍然允许子类(1)拥有自己的行为和(2)有选择地覆盖父类/默认行为

  • 创建一个自定义 JUnit runner,在这个 runner 中定义共享行为,然后使用@RunWith(YourCustomRunner.class)注释相关的测试用例。 有关此方法的更多详细信息,请点击此处

只是重申其他一些海报所说的话; 这不是常见的第一步,因此您可能更喜欢从简单的开始,如果您的使用提供了一个令人信服的理由,则只转向套件或抽象类或自定义运行器。

假设您希望对 2 个不同的类运行完全相同的测试(而不是像示例代码中那样模拟它),您可以创建一个抽象测试类,该类具有返回要测试的类的实例的抽象方法。

有以下特点:

public abstract class TestCaseResourceTest {

  protected abstract TestCaseService1 getServiceToTest();

  @Before
  public void before() throws Exception {
    testCaseService1 = getServiceToTest();
    MockitoAnnotations.initMocks(this);
    beforeFileTest();
  }

  @Test
  public void test() {
    // do your test here
  }
}

public class ConcreteTest extends TestCaseResourceTest {
  protected TestCaseService1 getServiceToTest() {
    return new TestCaseService();
  }
}

public class ConcreteTest2 extends TestCaseResourceTest {
  protected TestCaseService1 getServiceToTest() {
    return new DifferentService();
  }
}

我遇到过这种情况,这是错误实现设计的标志。 我们谈论的是纯单元测试,我们准确地测试生产类中实现的内容。 如果我们需要重复测试,这意味着我们可能在实现中存在重复。

我是如何在我的项目中解决它的?

  1. 将公共逻辑提取到父服务类中并为其实施单元测试。
  2. 对于子服务,我仅针对那里的特定实施代码实施了测试。 没有了。
  3. 在真实环境中实施集成测试,两个服务都涉及并完全测试。

您是否考虑过使用 JUnit 5 及其http://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests

它允许您使用不同的输入重复使用您的测试。 这是文档中的一个示例,它说明了您现在可以使用 JUnit 5 做什么:

@ParameterizedTest
@ValueSource(strings = { "Hello", "World" })
void testWithStringParameter(String argument) {
    assertNotNull(argument);
}

但是您也可以创建返回输入数据的方法:

@ParameterizedTest
@MethodSource("stringProvider")
void testWithSimpleMethodSource(String argument) {
    assertNotNull(argument);
}

static Stream<String> stringProvider() {
    return Stream.of("foo", "bar");
}

在这里,我只使用字符串,但您实际上可以使用任何对象。

如果您使用的是 Maven,则可以添加这些依赖项以开始使用 JUnit 5:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-params</artifactId>
    <version>5.0.0-RC2</version>
    <scope>test</scope>
</dependency>

JUnit 5 唯一令人讨厌的地方是它还没有发布。

当从一个测试转到两个测试时,您不知道什么是重复代码,因此我发现将所有内容都放在一个测试方法中很有用。 在这种情况下,首先将 @Before 和 beforeFileTest 方法的内容内联到测试中。

然后您可以看到它只是需要更改的服务,因此您可以将除此之外的所有内容提取到从两个测试调用的辅助方法中。

此外,在您有两个调用相同辅助方法的测试并且对该测试覆盖率感到满意后,您可以考虑编写参数化测试。 例如 JunitParams: https : //github.com/Pragmatists/junitparams/wiki/Quickstart

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM