我继承了大量的 Junit 测试,但这些测试(除了大多数不工作)是实际单元测试和集成测试(需要外部系统、数据库等)的混合体。
所以我试图想出一种方法将它们真正分开,这样我就可以快速运行单元测试以及之后的集成测试。
选项是..
将它们拆分为单独的目录。移至 Junit4(从 v3 开始)并注释类以将它们分开。使用文件命名约定来说明类是什么,即 AdapterATest 和 AdapterAIntergrationTest。
3 的问题是 Eclipse 可以选择“在选定的项目/包或文件夹中运行所有测试”。因此,仅运行集成测试将变得非常困难。
2:冒着开发人员可能会开始在单元测试类中编写集成测试的风险,它只会变得混乱。
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 插件的默认配置,因此即使您说 <excludedGroups/>
或 <excludedGroups></excludedGroups>
,也会使用值 com.test.annotation.type.IntegrationTest
。
您也不能使用 none
,因为它必须是类路径上的接口(Maven 将检查这一点)。
笔记:
仅当 Maven 不自动切换到 JUnit 4 运行器时,才需要对 surefire-junit47 的依赖。使用 groups 或 excludeGroups 元素应该会触发切换。看这里。
上面的大部分代码都取自 Maven Failsafe 插件的文档。请参阅此页面上的“使用 JUnit 类别”部分。
在我的测试中,我发现当您使用 @RunWith() 注释运行套件或基于 Spring 的测试时,这甚至可以工作。
我们使用 Maven Surefire 插件来运行单元测试和 Maven Failsafe 插件来运行集成测试。单元测试遵循 **/Test*.java **/*Test.java **/*TestCase.java
命名约定,集成测试 - **/IT*.java **/*IT.java **/*ITCase.java
。所以这实际上是你的第三个选项。
在几个项目中,我们使用 TestNG 并为集成/单元测试定义不同的测试组,但这可能不适合您。
我会为了拥有它而升级到 Junit4 :)
您可以将它们分成不同的测试套件。我不知道它们在 Junit3 中是如何组织的,但在 Junit4 中应该很容易构建测试套件并将所有真正的单元测试放在其中一个中,然后使用第二个套件进行集成测试。
现在在 eclipse 中为这两个套件定义一个运行配置,您可以轻松地运行一个套件。这些套件也可以从自动化过程中启动,允许您在每次源代码更改时运行单元测试,并且可能每天或每小时只运行一次集成测试(如果它们真的很大)。
由于组织政策(和 Junit 3 遗留),我目前使用单独的目录,但我现在正在使用 Junit 4,我希望自己过渡到注释。
我不会过分担心开发人员将集成测试放在您的单元测试类中 - 如果需要,请在您的编码标准中添加一条规则。
我很想知道除了注释或物理分离类之外可能还有哪些其他解决方案..
使用 IfProfileValue spring 注释可以在不需要 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 参数以运行集成和单元测试。
没有一个正确的答案。正如您所解释的,有几种方法可以做到这一点。我已经完成了文件命名方案并将内容拆分到不同的目录中。
听起来把东西分成不同的目录可能对你更有效,这对我来说似乎更清楚一些,所以我倾向于这样做。
我不认为我会尝试注释,因为这对我来说似乎更细粒度。您真的希望这两种类型的测试混合在同一个文件中吗?我不会。