【发布时间】:2019-02-10 19:24:51
【问题描述】:
我有一些 Spring 测试可以启动应用程序上下文并测试一些服务。我能够使用 Maven 和通过 IDE 运行这些测试。现在我需要在无法访问 Maven 的另一台机器上运行这些测试。我的想法是创建一个测试 jar 并通过命令行运行它们。
所以我创建了一个自定义 Runner,它调用我需要的测试类,这些测试将启动 Spring 应用程序上下文并测试一些服务。
这里是示例代码:
我的自定义跑步者:
public class Main {
public static void main(String[] args) {
System.out.println("Running tests!");
JUnitCore engine = new JUnitCore();
engine.addListener(new TextListener(System.out));
engine.run(SpringSampleTest.class);
}
}
上面的运行器正在调用这个测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {AppConfig.class})
public class SpringSampleTest {
@Autowired
TestService testService;
@Test
public void testSimple() {
assertTrue("Test Simple", testService.isValid());
}
}
这是我的配置和服务
@Configuration
@ComponentScan(basePackages = {"mypackage"})
public class AppConfig {
}
@Service
public class TestService {
public boolean isValid() {
return true;
}
}
所以为了从 jar 中运行这些测试,我使用了 assembly-plugin 创建了一个可执行 jar,其中包含我所有的测试和依赖项(感谢这个答案 here)。现在,当我运行这个可执行 jar 时,我的自定义 runner(Main.java) 能够触发测试,但它没有加载 Spring Context 并且由于我的依赖项没有自动装配而失败并出现 NullPointer 异常。这是日志:
Running tests!
Sep 05, 2018 5:15:01 PM org.springframework.test.context.support.DefaultTestContextBootstrapper getDefaultTestExecutionListenerClassNames
INFO: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: []
Sep 05, 2018 5:15:01 PM org.springframework.test.context.support.DefaultTestContextBootstrapper getTestExecutionListeners
INFO: Using TestExecutionListeners: []
.E
Time: 0.007
There was 1 failure:
1) testSimple(com.c0deattack.cu.runners.SpringSampleTest)
java.lang.NullPointerException
at com.c0deattack.cu.runners.SpringSampleTest.testSimple(SpringSampleTest.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.runner.JUnitCore.run(JUnitCore.java:105)
at org.junit.runner.JUnitCore.run(JUnitCore.java:94)
at com.c0deattack.cu.runners.Main.main(Main.java:15)
FAILURES!!!
Tests run: 1, Failures: 1
有人可以指出我做错了什么吗?
我还添加了我的 pom.xml 和程序集描述符文件:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mypackage</groupId>
<artifactId>executable-tests</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>executable-tests</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.2.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>assembly</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>mypackage.Main</mainClass>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
描述符 - assembly.xml
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>fat-tests</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<unpack>true</unpack>
<scope>test</scope>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.directory}/test-classes</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>**/*.class</include>
</includes>
<useDefaultExcludes>true</useDefaultExcludes>
</fileSet>
</fileSets>
</assembly>
您可以在 github 中查看示例项目:https://github.com/SaiUpadhyayula/executabletests
【问题讨论】:
-
集成/单元测试应该与 maven 一起抛出,并且创建的工件(jar)不应包含任何测试代码。为什么需要在 maven 阶段之外测试代码?
-
@CRISTIANROMEROMATESANZ 我在问题中添加了更多详细信息,tl.dr:我想在我无法访问 Maven 的另一台机器上运行测试。因此,我想创建一个 jar 并从中执行测试。
-
你也应该在主函数中创建
spring context -
你有一个困难的要求。我看到两个选项,要么编写不使用 spring 上下文的测试(通过重载或基于环境选择的构建器),要么模拟你的 spring bean。
-
干得好赛!您在 Github 中的项目运行良好!