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

我继承了一个 Junit 测试负载,但是这些测试(除了大多数不能工作的测试)是实际单元测试和集成测试(需要外部系统、 db 等)的混合体。

因此,我试图想出一种方法来实际地将它们分离出来,这样我就可以很好地、快速地运行单元测试,然后再运行集成测试。

选择是. 。

  1. 将它们分割成单独的目录。

  2. 移动到 Junit4(来自 v3)并对类进行注释以分隔它们。

  3. 使用文件变数命名原则来说明类是什么,例如 AdapterATest 和 AdapterA 集成测试

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

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

他说: 这似乎是最好的解决办法,但我的直觉告诉我,一定还有更好的解决办法。

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

54850 次浏览

我会搬到 Junit4,只是因为它:)

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

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

由于组织策略(和 Junit 3遗留问题) ,我目前使用单独的目录,但是我现在正在 Junit 4上寻找转换到注释的方法。

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

我很想知道除了注释之外还有哪些其他解决方案,或者在物理上分离类。

我们使用 MavenSurefire 插件来运行单元测试,使用 MavenFalsafe 插件来运行集成测试。单元测试遵循 **/Test*.java **/*Test.java **/*TestCase.java命名约定,集成测试 -**/IT*.java **/*IT.java **/*ITCase.java。所以这是你的第三个选择。

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

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

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

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

您可以使用 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 插件的默认配置,所以即使您说 <excludedGroups/><excludedGroups></excludedGroups>,也将使用值 com.test.annotation.type.IntegrationTest

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

备注:

  • 只有当 Maven 不自动切换到 JUnit4运行程序时,才需要对 surefire-junit47的依赖。使用 groupsexcludedGroups元素应该触发开关。看这里.
  • 上面的大部分代码都是从 Maven 故障安全插件的文档中获取的。请参阅“使用 JUnit 类别”一节。
  • 在我的测试中,我发现当您使用 @RunWith()注释来运行套件或基于 Spring 的测试时,这种方法甚至可以工作。

使用 IfProfileValue春季注释 使得有可能实现这个 没有一个专家插件或配置的要求。

使用 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 参数以运行集成测试和单元测试。