一般问题:我正在一家面向服务架构的大公司测试Web应用程序。由于背景噪音,外部服务通常在我们的测试环境中失败。这可以防止我们的服务集成测试正常运行,因为除非对这些外部服务的调用成功,否则我们的服务将无法正常工作。出于这个原因,我们希望能够模拟来自外部服务的响应,这样我们就不必依赖它们,并且可以单独测试我们自己的服务。
我们希望使用这个名为Mockey的工具。它是一个Java程序,它通过嵌入式Jetty服务器运行,并充当服务调用的代理。我们的Web应用程序重新配置为调用Mockey而不是外部服务。然后,Mockey被配置为根据传入的URL和标头数据提供对这些调用的动态模拟响应。
为了使用这个工具,我们希望能够在Maven生命周期的预集成测试阶段启动Mockey,以便在集成测试阶段可以使用它。
具体问题:为了在Maven生命周期的预集成测试和集成后测试阶段启动和关闭Mockey,我编写了一个名为mockey的Maven 3插件-maven-插件:
mockey-maven-plugin pom.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<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>com.mycompany.mockey</groupId>
<artifactId>mockey-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>1.3</version>
<dependencies>
<!-- Maven plugin dependencies -->
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.4</version>
<scope>provided</scope>
</dependency>
<!-- Mockey dependency -->
<dependency>
<groupId>com.mycompany.mockey</groupId>
<artifactId>Mockey</artifactId>
<version>1.16.2015</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- This plugin is used to generate a plugin descriptor
xml file which will be packaged with the plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.4</version>
</plugin>
</plugins>
</build>
</project>
mockey-maven-plugin StartMockey课程:
@Mojo(name="start-mockey")
@Execute(phase= LifecyclePhase.PACKAGE) // Not sure about this annotation
public class StartMockey extends AbstractMojo
{
/**
* Flag which controls Mockey startup.
*/
@Parameter(property="mockey.skipStartup", defaultValue="false", required=true)
private Boolean skipStartup;
// Do I need these getters and setters or does Maven ignore them?
public Boolean getSkipStartup()
{
return skipStartup;
}
public void setSkipStartup(Boolean skipStartup)
{
this.skipStartup = skipStartup;
}
// *SNIP* Defining Mockey parameters...
// Maven will call this method to start the mockey-maven-plugin
public void execute()
{
if(skipStartup)
{
getLog().info("Skipping Mockey startup");
return;
}
getLog().info("Starting Mockey");
// Load specified parameters into array
List<String> argsList = new ArrayList<>();
// *SNIP* Adding Mockey parameters to argList...
String[] args = new String[argsList.size()];
argsList.toArray(args);
// Start Mockey with specified parameters and wait for it to return
try
{
JettyRunner.main(args);
}
catch(Exception e)
{
getLog().error("Mockey died... :(");
}
getLog().info("mockey-maven-plugin now exiting");
}
}
mockey-maven-plugin ShutdownMockey课程:
@Mojo(name="shutdown-mockey")
public class ShutdownMockey extends AbstractMojo
{
/**
* Flag which controls Mockey shutdown.
*/
@Parameter(property="mockey.skipShutdown")
private Boolean skipShutdown;
// Again, Do I need these getters and setters or does Maven ignore them?
public Boolean getSkipShutdown()
{
return skipShutdown;
}
public void setSkipShutdown(Boolean skipShutdown)
{
this.skipShutdown = skipShutdown;
}
public void execute()
{
if(skipShutdown)
{
getLog().info("Skipping Mockey shutdown");
return;
}
getLog().info("Shutting down Mockey");
JettyRunner.stopServer();
getLog().info("mockey-maven-plugin now exiting");
}
}
我团队项目的pom.xml文件中mockey-maven-plugin的插件条目:
<plugin>
<groupId>com.mycompany.mockey</groupId>
<artifactId>mockey-maven-plugin</artifactId>
<version>1.3</version>
<configuration>
<skipShutdown>${keepMockeyRunning}</skipShutdown>
<skipStartup>${skipMockey}</skipStartup>
<!-- *SNIP* Other Mockey parameters... -->
</configuration>
<executions>
<execution>
<id>start-mockey</id>
<goals>
<goal>start-mockey</goal>
</goals>
<phase>pre-integration-test</phase>
</execution>
<execution>
<id>shutdown-mockey</id>
<goals>
<goal>shutdown-mockey</goal>
</goals>
<phase>post-integration-test</phase>
</execution>
</executions>
</plugin>
此插件适用于在预集成测试阶段启动Mockey,但阻止构建直到Mockey退出。我不确定为什么会这样,因为我专门添加了这个注释来防止这个问题:
@Execute(phase= LifecyclePhase.PACKAGE)
我实际上从另一个插件中复制了这个注释,这正是我在这里尝试做的事情(我们使用maven-tomcat7-plugin在预集成测试阶段在本地启动我们的Web应用程序并关闭它在集成后测试阶段。我认为这会以同样的方式运作,但我看到了不同的行为。
以下是我想要看到的内容:
以下是我实际看到的情况:
这让我感到困惑,主要是因为Maven似乎有一个不同于我所熟悉的分叉概念。对我来说,分叉意味着在某个特定点发散,而不是重新开始,而不是影响原始过程。当我们在Unix中分叉一个进程时,它会复制第一个进程的堆栈和函数指针。它不会从程序的开头重新开始。类似地,当我们分叉代码存储库时,我们从当前存储库中的所有文件和目录开始。我们不会重新开始一片空白。那么,为什么,当我们&#34; fork&#34; Maven生命周期是否会放弃所有内容,重新开始并阻止原始线程?这根本不像是向我求助。这是我读过的一些描述&#34;分叉&#34;在Maven:
剩余问题:
已回答的问题(见下文): - 是否有另一个阶段,我应该在我的插件的注释中指定它以使其按照需要运行,还是应该以一种根本不同的方式使用执行注释?
答案 0 :(得分:4)
请参阅https://books.sonatype.com/mvnref-book/reference/writing-plugins-sect-plugins-lifecycle.html
文档似乎表明您应该创建一个仅包含开始 - 曲棍球目标的自定义生命周期。然后,您的@Execute注释应指定目标和生命周期。这应该分开执行,但只执行你的开始曲棍球。我想你可以正常运行终极骑师。
答案 1 :(得分:2)
我仍然不明白Maven正在做什么,但我找到了解决问题的方法:
StartMockey.execute()中新代码的片段:
// Start Mockey with the specified parameters on a new thread.
MockeyRunner mockeyRunner = new MockeyRunner(args);
mockeyRunnerThread = new Thread(mockeyRunner);
mockeyRunnerThread.start();
新的MockeyRunner课程:
public class MockeyRunner implements Runnable
{
private String[] args;
private Exception exception;
/**
* We cannot throw the Exception directly in run() since we're implementing the runnable interface which does not
* allow exception throwing. Instead we must store the exception locally and check for it in whatever class is
* managing this MockeyRunner instance after the run method has returned.
* @return Exception thrown by Mockey
*/
public Exception getException()
{
return exception;
}
/**
* Constructor
* @param args The arguments to pass to Mockey on startup
*/
public MockeyRunner(String[] args)
{
this.args = args;
}
/**
* This method starts Mockey from inside a new Thread object in an external class. It is called internally by Java
* when the Thread.start() method is called on that object.
*/
@Override
public void run()
{
try
{
JettyRunner.main(args);
}
catch(Exception e)
{
exception = e;
}
}
}
我不会接受这个解决方案作为答案。虽然它解决了我的问题,但我仍然想知道Maven“forking”的全部内容!