Junit:拆分集成测试和单元测试

Posted

技术标签:

【中文标题】Junit:拆分集成测试和单元测试【英文标题】:Junit: splitting integration test and Unit tests 【发布时间】:2011-02-06 02:05:25 【问题描述】:

我继承了大量的 Junit 测试,但这些测试(除了大多数不起作用)是实际单元测试和集成测试(需要外部系统、数据库等)的混合体。

所以我正在尝试想办法将它们真正分开,以便我可以快速运行单元测试以及之后的集成测试。

选项是..

    将它们拆分为单独的目录。

    移至 Junit4(从 v3 开始)并注释类以将它们分开。

    使用文件命名约定来说明类是什么,即 AdapterATest 和 AdapterAIntergrationTest.

3 的问题是 Eclipse 可以选择“在选定的项目/包或文件夹中运行所有测试”。因此,仅运行集成测试会变得非常困难。

2:冒着开发人员可能会开始在单元测试类中编写集成测试的风险,并且会变得混乱。

1:似乎是最巧妙的解决方案,但我的直觉认为肯定有更好的解决方案。

这就是我的问题,您如何将集成测试和适当的单元测试分开?

【问题讨论】:

我只想感谢大家的投入,我知道这是一个主观问题,并没有一个正确的答案。但是您帮助我意识到除了我列出的选项之外没有其他选择。我想我现在将使用目录结构并转移到 JUnit4,尽管目前还没有使用注释来拆分它们。 【参考方案1】:

您可以使用 JUnit 类别和 Maven 轻松拆分它们。

下面通过拆分单元测试和集成测试非常非常简要地展示了这一点。

定义一个标记接口

使用类别对测试进行分组的第一步是创建标记界面。

此接口将用于将您要运行的所有测试标记为集成测试。

public interface IntegrationTest 

标记您的测试课程

将类别注释添加到测试类的顶部。它采用新界面的名称。

import org.junit.experimental.categories.Category;
@Category(IntegrationTest.class)
public class ExampleIntegrationTest
  @Test
  public void longRunningServiceTest() throws Exception 
  

配置 Maven 单元测试

这个解决方案的美妙之处在于,单元测试方面并没有真正改变。

我们只需向 maven surefire 插件添加一些配置,使其忽略任何集成测试。

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <includes>
      <include>**/*.class</include>
    </includes>
    <excludedGroups>com.test.annotation.type.IntegrationTest</excludedGroups>
  </configuration>
</plugin>

当您执行 mvn clean 测试时,只会运行未标记的单元测试。

配置 Maven 集成测试

同样,此配置非常简单。

要仅运行集成测试,请使用以下命令:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <groups>com.test.annotation.type.IntegrationTest</groups>
  </configuration>
</plugin>

如果将其包装在 ID 为 IT 的配置文件中,则只能使用 mvn clean install 运行快速测试。要仅运行集成/慢速测试,请使用 mvn clean install -P IT

但大多数情况下,您会希望默认运行快速测试并使用-P IT 运行所有 测试。如果是这样的话,那你就得用个技巧了:

<profiles>
    <profile>
        <id>IT</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <excludedGroups>java.io.Serializable</excludedGroups> <!-- An empty element doesn't overwrite, so I'm using an interface here which no one will ever use -->
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

如您所见,我排除了带有java.io.Serializable 注释的测试。这是必要的,因为配置文件将继承 Surefire 插件的默认配置,因此即使您说 &lt;excludedGroups/&gt;&lt;excludedGroups&gt;&lt;/excludedGroups&gt;,也会使用值 com.test.annotation.type.IntegrationTest

你也不能使用none,因为它必须是类路径上的一个接口(Maven 会检查这个)。

注意事项:

仅当 Maven 不自动切换到 JUnit 4 运行器时,才需要对 surefire-junit47 的依赖。使用groupsexcludedGroups 元素应该会触发切换。 See here。 上面的大部分代码取自 Maven Failsafe 插件的文档。请参阅“使用 JUnit 类别”on this page 部分。 在我的测试中,我发现当您使用 @RunWith() 注释运行套件或基于 Spring 的测试时,这甚至可以正常工作。

【讨论】:

我认为您的最后一个 pom.xml 片段中有错误。您粘贴了与“测试”阶段相同的 sn-p。它仍然排除了集成测试,也没有绑定到任何 Maven 阶段。 确实,最后一个 pom 片段是复制粘贴错误。它应该显示 maven-failsafe-plugin。 那么第二个xml应该是什么? :O 如果你使用默认的 Maven 配置文件,你不必使用这个技巧(Serializable 的最后一个魔法) 这确实应该是公认的答案,因为这实际上是一个问题的解决方案,而不是关于在哪里放置不同测试的哲学辩论。【参考方案2】:

我们使用 Maven Surefire 插件运行单元测试,使用 Maven Failsafe 插件运行集成测试。单元测试遵循 **/Test*.java **/*Test.java **/*TestCase.java 命名约定,集成测试 - **/IT*.java **/*IT.java **/*ITCase.java。所以这实际上是你的第三个选项。

在几个项目中,我们使用 TestNG 并为集成/单元测试定义了不同的测试组,但这可能不适合您。

【讨论】:

+1 用于 maven + surefire + failsafe + junit 组合。我没有意识到故障保护会自动运行“IT *”。甜蜜。【参考方案3】:

我会因为拥有它而升级到 Junit4 :)

您可以将它们分成不同的测试套件。我不知道它们在 Junit3 中是如何组织的,但在 Junit4 中应该很容易构建测试套件并将所有真正的单元测试放在其中一个中,然后使用第二个套件进行集成测试。

现在在 eclipse 中为这两个套件定义一个运行配置,您可以轻松地运行一个套件。这些套件也可以从自动化流程启动,允许您在每次源代码更改时运行单元测试,并且可能每天或每小时只运行一次集成测试(如果它们真的很大)。

【讨论】:

【参考方案4】:

由于组织政策(以及 Junit 3 遗留问题),我目前使用单独的目录,但我现在正在使用 Junit 4,我希望自己过渡到注释。

我不会过分担心开发人员将集成测试放在您的单元测试类中 - 如有必要,请在您的编码标准中添加一条规则。

我很想知道除了注释或物理分离类之外可能还有哪些其他解决方案..

【讨论】:

【参考方案5】:

使用IfProfileValuespring注解 无需 maven 插件或配置即可实现这一目标。

使用 IfProfileValue 注释集成测试类或方法

import org.springframework.test.annotation.IfProfileValue;

@IfProfileValue(name="test-groups", value="integration")
public class ExampleIntegrationTest
    @Test
    public void longRunningServiceTest() throws Exception 
    
 

仅使用单元测试运行:

mvn clean test

使用集成测试和单元测试运行:

mvn clean test -Dtest-groups=integration

此外,IDE 中的“运行所有测试”将仅运行单元测试。将 -Dtest-groups=integration 添加到 VM 参数以运行集成和单元测试。

【讨论】:

这种方法既好又简单,但我发现的问题是默认情况下我想运行所有测试(包括集成测试)。用这种方法是不可能的,是吗?【参考方案6】:

没有一个正确的答案。正如您所解释的,有几种方法可以做到这一点。我已经完成了文件命名方案并将内容拆分到不同的目录。

听起来把东西分成不同的目录可能对你更有效,这对我来说似乎更清楚一些,所以我倾向于这样做。

我不认为我会尝试注释,因为这对我来说似乎更细粒度。您真的希望这两种类型的测试混合在同一个文件中吗?我不会。

【讨论】:

以上是关于Junit:拆分集成测试和单元测试的主要内容,如果未能解决你的问题,请参考以下文章

使用junit进行集成spring项目的单元测试

使用junit进行集成spring项目的单元测试

如何使用注释在 testng + maven 中分离单元测试和集成测试?

使用 Micronaut 应用程序为 JUnit5 中的每个单元/集成测试运行一次 TestContainer

Springboot集成JUnit5优雅进行单元测试

SpringBoot 集成JUnit