templates.docs.testing.html Maven / Gradle / Ivy
Show all versions of spincast-website Show documentation
{#==========================================
Docs : "Testing"
==========================================#}
Testing
Spincast provides some nice testing utilities. You
obviously don't have to use those to test your Spincast application,
you may already have your favorite testing toolbox and be happy with it.
But those utilities are heavily used to test
Spincast itself, and we think they are an easy, fun, and very solid testing foundation.
First, Spincast comes with a custom JUnit runner which allows testing
using a Guice context really easily. But, the biggest feature is to be able
to test your real application itself, without even changing the
way it is bootstrapped. This is possible because of the Guice Tweaker
component which allows to indirectly mock or extend some components.
{#==========================================
Installation
==========================================#}
Installation
Add this Maven artifact to your project to get access to the Spincast testing utilities:
<dependency>
<groupId>org.spincast</groupId>
<artifactId>spincast-testing-default</artifactId>
<version>{{spincast.spincastCurrrentVersion}}</version>
<scope>test</scope>
</dependency>
Then, make your test classes extend SpincastTestBase
or one of its children classes.
Most of the time, you'll want to extend
AppBasedTestingBase, or
AppBasedDefaultContextTypesTestingBase
if your application uses the default request context types.
{#==========================================
Testing demo
==========================================#}
Demo
In this demo, we're going to test a simple application which only has
one endpoint : "/sum"
. The Route Handler
associated with this endpoint is going to receive two numbers, will
add them up, and will return the result as a
Json
object. Here's the response we would be expecting from the "/sum"
endpoint when sending the
parameters "first" = "1"
and "second" = "2"
:
{
"result": "3"
}
You can download that Sum application [.zip]
if you want to try it by yourself or look at its code directly.
First, let's have a quick look at how the demo application is bootstrapped :
public class App {
public static void main(String[] args) {
Spincast.configure()
.module(new AppModule())
.init(args);
}
@Inject
protected void init(DefaultRouter router,
AppController ctrl,
Server server) {
router.POST("/sum").handle(ctrl::sumRoute);
server.start();
}
}
The interesting lines to note here are 4-6 : we
use the standard Bootstrapper to start
everything! We'll see that, without modifying
this bootstrapping process, we'll still be able to tweak the Guice context, to mock
some components.
Let's write a first test class :
public class SumTest extends AppBasedDefaultContextTypesTestingBase {
@Override
protected void callAppMainMethod() {
App.main(null);
}
@Override
protected AppTestingConfigs getAppTestingConfigs() {
return new AppTestingConfigs() {
@Override
public boolean isBindAppClass() {
return true;
}
@Override
public Class<? extends SpincastConfig> getSpincastConfigTestingImplementationClass() {
return SpincastConfigTestingDefault.class;
}
@Override
public Class<?> getAppConfigTestingImplementationClass() {
return null;
}
@Override
public Class<?> getAppConfigInterface() {
return null;
}
};
}
@Inject
private JsonManager jsonManager;
@Test
public void validRequest() throws Exception {
// TODO...
}
}
Explanation :
-
2 : Our test class extends
AppBasedDefaultContextTypesTestingBase.
This class is a child of SpincastTestBase and therefore allows
us to use all the tools Spincast testing provides. Note there are other base classes you can extend, we're going to
look at them soon.
-
4-7 : The base class we are using requires that we implement the
callAppMainMethod()
method. In this method we have to initialize the application to test. This is
easily done by calling its main(...)
method.
-
9-33 : We also have to implement the
getAppTestingConfigs()
method. This is to provide Spincast informations about the configurations we want to use when running
this test class. Have a look at the Testing configurations
section for more information!
-
35-36 : Here we can see Spincast testing in action! Our
test class has now full access to the Guice context of the application. Therefore, we
can inject any component we need. In this test class, we are going to
use the JsonManager.
-
38-41 : a first test to implement.
As you can see, simply by extending AppBasedDefaultContextTypesTestingBase
, and by starting our
application using its main(...)
method, we can write integration tests targeting
our running application, and we can use any components from its Guice context. There is some boilerplate
code to write though (you nee to implement the getAppTestingConfigs()
method, for example), and this why
you would in general create a base class to serve as a parent for all your test classes!
Let's implement our first test. We're going to validate that the "/sum"
endpoint
of the application works properly :
//...
@Test
public void validRequest() throws Exception {
HttpResponse response = POST("/sum").addFormBodyFieldValue("first", "1")
.addFormBodyFieldValue("second", "2")
.addJsonAcceptHeader()
.send();
assertEquals(HttpStatus.SC_OK, response.getStatus());
assertEquals(ContentTypeDefaults.JSON.getMainVariationWithUtf8Charset(),
response.getContentType());
String content = response.getContentAsString();
assertNotNull(content);
JsonObject resultObj = this.jsonManager.fromString(content);
assertNotNull(resultObj);
assertEquals(new Integer(3), resultObj.getInteger("result"));
assertNull(resultObj.getString("error", null));
}
Explanation :
-
6-9 : the Spincast HTTP Client
plugin is fully integrated into Spincast testing utilities. This allows us to
very easily send requests to test our application. We don't even have to
configure the host and port to use : Spincast will
automatically find and use those of our application.
-
11-13 : we validate that the response is a success
(
"200"
) and that the content-type is the expected
"application/json"
.
-
15-16 : we get the content of the response as a String and we validate that
it is not
null
.
-
18-19 : we use the
JsonManager
(injected previously) to convert the content to a JsonObject.
-
21-22 : we finally validate the result of the sum
and that no error occured.
Note that we could also have retrieved the content of the response as a JsonObject
directly, by using response.getContentAsJsonObject()
instead of
response.getContentAsString()
. But we wanted to demonstrate the use of
an injected component, so bear with us!
If you look at the source
of this demo, you'll see two more tests in that first test class : one that
tests the endpoint when a parameter is missing, and one that tests the endpoint when the sum overflows
the maximum Integer
value.
Let's now write a second test class. In this one, we are going to show how
easy it is to replace a binding, to mock a component.
Let's say we simply want to test that the responses returned by our application
are gzipped. We may not care about the actual result of calling the
"/sum"
endpoint, so we are going to "mock" it. This is a simple
example, but the process involved is similar if you need to mock a
data source, for example.
Our second test class will look like this :
public class ResponseIsGzippedTest extends AppBasedDefaultContextTypesTestingBase {
@Override
protected void callAppMainMethod() {
App.main(null);
}
@Override
protected AppTestingConfigs getAppTestingConfigs() {
return new AppTestingConfigs() {
@Override
public boolean isBindAppClass() {
return true;
}
@Override
public Class<? extends SpincastConfig> getSpincastConfigTestingImplementationClass() {
return SpincastConfigTestingDefault.class;
}
@Override
public Class<?> getAppConfigTestingImplementationClass() {
return null;
}
@Override
public Class<?> getAppConfigInterface() {
return null;
}
};
}
public static class AppControllerTesting extends AppControllerDefault {
@Override
public void sumRoute(DefaultRequestContext context) {
context.response().sendPlainText("42");
}
}
@Override
protected Module getExtraOverridingModule() {
return new SpincastGuiceModuleBase() {
@Override
protected void configure() {
bind(AppController.class).to(AppControllerTesting.class).in(Scopes.SINGLETON);
}
};
}
@Test
public void isGzipped() throws Exception {
// TODO...
}
}
Explanation :
-
2 : this test class also extends
AppBasedDefaultContextTypesTestingBase.
-
4-7 : we start our application.
-
9-33 : if we had created a base class for our tests, we could have
define the
getAppTestingConfigs()
there instead of having to repeat it in all test
files!
-
35-41 : we create a mock controller by extending
the original one and replacing the
sumRoute(...)
Route Handler
so it always returns "42".
-
43-52 : We specify an overriding module to change the implementation
that will be used for the
AppController
binding. Under the hood, this is done
by the Guice Tweaker.
And let's write the test itself :
//...
@Test
public void isGzipped() throws Exception {
HttpResponse response = POST("/sum").addFormBodyFieldValue("toto", "titi")
.addJsonAcceptHeader()
.send();
assertTrue(response.isGzipped());
assertEquals(HttpStatus.SC_OK, response.getStatus());
assertEquals(ContentTypeDefaults.TEXT.getMainVariationWithUtf8Charset(),
response.getContentType());
assertEquals("42", response.getContentAsString());
}
Explanation :
-
6-8 : We can send pretty much anything here as the
parameters since the controller is mocked : they won't be validated.
-
10 : We validate that the response was gzipped.
-
12-15 : just to make sure our tweaking
is working properly.
Being able to change bindings like this is very powerful : you are testing your real application,
as it is bootstrapped, without even changing its code. All is done indirectly, using
the Guice Tweaker.
{#==========================================
Guice Tweaker
==========================================#}
Guice Tweaker
As we saw in the previous demo, we can tweak the Guice context of our application
in order to test it. This is done by the
GuiceTweaker,
a component which is part of the Spincast testing machanism.
The Guice Tweaker is in fact a plugin. This plugin is special because
it is applied even if it's not registered during the bootstrapping of the application.
It's important to know that the Guice Tweaker only works if you are using the
standard Bootstrapper. It is implemented
using a ThreadLocal
that the bootstrapper will look for.
The Guice Tweaker is created in the SpincastTestBase
class. By extending this class or one of its children, you have access to it.
By default, the Guice Tweaker automatically modifies the SpincastConfig
binding of the application when tests are run. This allows you to use testing configurations very easily
(for example to make sure the server starts on a free port). The implementation class used
for those configurations are specified in the getAppTestingConfigs()
method you have to implement. The Guice tweaker will use those informations and will create the required binding
automatically. The default implementation for the SpincastConfig
interface is
SpincastConfigTestingDefault.
Those are the methods available, in a test file, to tweak your application :
-
getAppTestingConfigs(...) : a section dedicated to this method
follows next.
-
getExtraOverridingModule(...) : to make the Guice Tweaker
add an extra module to the created Guice context.
-
getExtraPlugins(...) : to make the Guice Tweaker
add extra plugins to the created Guice context.
-
addExtraSystemProperties(...) : to add extra System properties
before running the tests.
{#==========================================
Testing configurations
==========================================#}
The testing configurations (getAppTestingConfigs()
)
When running integration tests, you don't want to use the same configurations than the ones
you would when running the application directly. For example, you may want to provide a
different connection string
to use a mocked database instead of the real one.
As we saw in the previous section, the Guice Tweaker allows you to
change some bindings when testing your application. But configurations is such an important component
to modify, when running tests, that Spincast forces you to specify which implementations to use for
those!
You specify the testing configurations by implementing the
getAppTestingConfigs()
method. This method must return an instance of
AppTestingConfigs. This
object tells Spincast :
-
getSpincastConfigTestingImplementationClass() : The implementation class to use for
the
SpincastConfig
binding. In other words, this hook allows you to easily mock the
configurations used by Spincast core components. The default testing implementation is the provided
SpincastConfigTestingDefault
class. You can use this provided class directly, or at least you may want to have a look at it when writing
your own since it shows how to implement some useful things, such as finding a free port to use when starting the HTTP server
during tests.
-
getAppConfigInterface() : The interface of your custom app configurations
class. You can return
null
if you don't have a custom configurations class.
-
getAppConfigTestingImplementationClass() : The implementation class to use for
your custom app configurations. You can return
null
if you don't have a custom configurations class.
-
isBindAppClass() : Should the App class itself (the class in which
Spincast.init()
or Spincast.configure()
is called) be bound?
In general, if you are running
unit tests and don't need to start any HTTP server, you are going to
return false
... That way, your main class
(in general named "App
") won't be bound and therefore won't start the
server.
Spincast will use the informations returned by this object and will add all the required bindings
automatically. You don't need to do anything by yourself, for example by using the Guice Tweaker, to change the
bindings for the configurations when running integration tests. You just need to implement the
getAppTestingConfigs()
method.
In most applications, the testing implementation to use for the SpincastConfig
interface and
the one for your
custom configurations interface will be the same! Indeed, if you follow
the suggested way of configuring your application, then your custom
configurations interface AppConfig
extends SpincastConfig
.
In that case, Spincast will automatically intercept calls to methods made on the
AppConfig
instance, but that are defined
in the parent SpincastConfig
interface, and will route them to the
SpincastConfig testing implementation (as
returned by getSpincastConfigTestingImplementationClass()
. Doing so, you can specify a config
in the testing implementation (the HTTPS port to use, for example), and that config
will be used in your app.
Note that you can annotate a method with
@DontIntercept
if you don't want it to
be intercepted.
Your testing configurations can often be shared between multiple tests classes.
It is therefore a good idea to create an abstract base class, named "AppTestingsBase" or something similar,
to implement the getAppTestingConfigs()
method there, and use
this base class as the parent for all your integration test classes. Have a look at
this base class
for an example.
While mocking some configurations is often required, it's still a good
idea to make testing configurations as close as possible as the ones that are going to be used
in production. For example, returning false
for the
isDevelopmentMode()
method is suggested. That way, you can be confident that once your tests pass, your application will do well
in production.
You can mock some Environment Variables used as configurations, by overriding the
getEnvironmentVariables()
method in your configurations implementation class.
{#==========================================
Testing base classes
==========================================#}
Testing base classes
Multiple base classes are provided, depending on the needs of your test class. They all ultimately extend
SpincastTestBase,
they all use the Spincast JUnit runner and
all give access to Guice Tweaker.
Those test base classes are split into two main categories : those based on your actual application and those
that are not. Most of the time, you do want to test using the Guice context of your application! But you may
sometimes have components that can be unit tested without the full Guice context of your application.
Those are the main testing base classes provided by Spincast. All of them can be modify using the Guice Tweaker :
App based
-
AppBasedTestingBase :
probably the most useful class. Using this class as a parent, your full application Guice context will be used
to run the tests.
-
AppBasedDefaultContextTypesTestingBase :
Same as
AppBasedTestingBase
, but if you use the default request context type in your application, instead of
a custom one.
Not based on an app
-
NoAppTestingBase : base class
to use to test components using the default Guice context (the default plugins only). No application class is involved.
-
NoAppStartHttpServerTestingBase :
as
NoAppTestingBase
, but if you also need the HTTP server to be started! This base class will be responsible to
start and stop the server.
{#==========================================
Spincast JUnit runner
==========================================#}
Spincast JUnit runner
Spincast's testing base classes all use a custom JUnit runner:
SpincastJUnitRunner.
This custom runner has a couple of differences as compared with the default JUnit runner,
but the most important one is that instead of creating a new instance of the test class
before each test, this runner only creates one instance.
This way of running the tests works very well when a Guice context is involved.
The Guice context is created when the test class is initialized, and then this context is used to run all the tests
of the class. If Integration testing is used, then the HTTP Server
is started when the test class is initialized and it is used to run
all the tests of the class.
Let's see in more details how the Spincast JUnit runner works :
-
First, if your test class (or a parent) implements
the CanBeDisabled
interface and the
isTestClassDisabledPreBeforeClass()
method returns true
, the
test class is ignored (the Guice context is not even created).
-
The
beforeClass()
method is called. As opposed to a classic
JUnit's @BeforeClass
annotated method, Spincast's beforeClass()
method is
not static. It is called when the test class is initialized.
-
The
createInjector()
method is called in the beforeClass()
method. This is where
the Guice context will be created, by starting an application or explictly.
-
The dependencies are automatically injected from the Guice context into the instance of the test class.
All your
@Inject
annotated fields and methods are fulfilled.
-
If an exception occures during the execution of the
beforeClass()
method,
the beforeClassException(...)
method will be called, the process will be stop and the tests won't be run.
-
If your test class (or a parent) implements
the CanBeDisabled
interface and the
isTestClassDisabledPostBeforeClass()
method returns true
, the
tests are all ignored (but the Guice context is created and you have access to it to perform the logic required
to determine if tests must be ignored or not).
-
The tests are run.
-
The
afterClass()
method is called. Like the beforeClass()
method, this
method is not static. Note that the afterClass()
method won't be called if an exception occurred
in the beforeClass()
method.
Since the Guice context is shared by all the tests of a test class, you have to make sure you reset everything
required before running a test. To do this, use JUnit's
@Before annotation, or
the beforeTest()
and afterTest()
method.
Spincast JUnit runner features
-
If your test class is annotated with
@ExpectingBeforeClassException
then the
beforeClass()
method is expected to throw an exception! In other words, the test class will be
shown by JUnit as a "success" only of the beforeClass()
method throws an exception. This is useful,
in integration testing, to validate that your application refuses some invalid configuration when
it starts, for example.
-
If your test class (or a parent) implements
TestFailureListener
then the
testFailure(...)
method will be called each time a test fails. This
allows you to add a breakpoint or some logs, and to inspect the context of the failure.
-
The @RepeatUntilFailure annotation
makes your test class loop until an error occurs or the specified number of loops is reached. This can be useful to debug
tests that sometimes fail and you need a way to run them over and over until they do fail.
Note that the beforeClass()
and afterClass()
methods will also be called X number of time, so the
Guice context will be recreated each time.
You can specify a number of milliseconds to sleep between two loops, using the sleep
parameter.
This annotation can also be used on a single test method too. In that case, only the annotated test method will be looped over.
-
The @RepeatUntilSuccess annotation
makes your test class loop until all tests pass or the specified number of loops is reached.
It is a bad practice to use this annotation without good reasons! Tests should always be replicable. You should not
have to run a test multiple time for it to actually pass! But, in seldom situations where you are not able to
make a test pass 100% of the time, and you consciously decide that the test is ok like it is, then this annotation
can help.
You can specify a number of milliseconds to sleep between two loops, using the sleep
parameter.
This annotation can also be used on a single test method.
In that case, only the annotated test method will be looped until it passes or the maximum number of loops is reached.
-
The @ExpectingFailure annotation
will make your test class pass when at least one test fails. It will make the test class fails
if all tests pass.
-
If your test class (or a parent) implements
RepeatedClassAfterMethodProvider
then the
afterClassLoops()
method will be called when all the loops of the test class have been
run.
{#==========================================
Managing cookies
==========================================#}
{#==========================================
Spincast Testing databases
==========================================#}
Embedded databases for testing
Two embedded databases are provided for testing: H2
and a PostgreSQL.
Those two allow you to run your tests on a real but ephemeral database.
Use the H2 database if your queries are simple and you want fast tests. Use PostgreSQL
when you need "the real thing", even if it's slower to bootstrap.
H2
H2 is a very fast database to use to run tests. Its drawback is that is may not always support all
real-world kind of queries, but other than that it does its job very well...
You enable the Spincast Testing H2 database simply by binding SpincastTestingH2
as a Provider for your DataSource
:
@Override
protected Module getExtraOverridingModule() {
return Modules.override(super.getExtraOverridingModule()).with(new SpincastGuiceModuleBase() {
@Override
protected void configure() {
bind(DataSource.class).toProvider(SpincastTestingH2.class).in(Scopes.SINGLETON);
// ...
}
});
}
You then inject SpincastTestingH2
and the
DataSource
in your test file (or a base class):
@Inject
protected SpincastTestingH2 spincastTestingH2;
@Inject
private DataSource testDataSource;
In beforeClass()
, you can make sure the database starts in a clean state:
@Override
public void beforeClass() {
super.beforeClass();
spincastTestingH2.clearDatabase();
}
... you can also do this before each test, if required:
@Override
public void beforeTest() {
super.beforeTest();
spincastTestingH2.clearDatabase();
}
When the tests are over, you stop the server:
@Override
public void afterClass() {
super.afterClass();
spincastTestingH2.stopServer();
}
The way the H2 server is started, you are able to connect to your database using
an external tool. For example, you can set a breakpoint and open the database using
DBeaver (or another tool) using the
proper connection string ("jdbc:h2:tcp://localhost:9092/mem:test;MODE=PostgreSQL;DATABASE_TO_UPPER=false
" for example).
This allows you to easily debug your tests.
You can change some configurations used by Spincast Testing H2 (the server port
for example) by binding a custom implementation
of the SpincastTestingH2Config interface.
If you don't, the default configurations
will be used.
PostgreSQL
The PostgreSQL (or simply Postgres) database provided by Spincast is based on
otj-pg-embedded. It is a
standalone version of PostgreSQL (no installation required) that can be used to run your tests.
It is slower to start than H2 to run a tests file, but it is a real PostgreSQL database,
so you can run any real-world SQL on it!
You enable it simply by binding
SpincastTestingPostgres
as a Provider for your DataSource
:
@Override
protected Module getExtraOverridingModule() {
return Modules.override(super.getExtraOverridingModule()).with(new SpincastGuiceModuleBase() {
@Override
protected void configure() {
bind(DataSource.class).toProvider(SpincastTestingPostgres.class).in(Scopes.SINGLETON);
// ...
}
});
}
You then inject SpincastTestingPostgres
and the
DataSource
in your test file (or a base class):
@Inject
protected SpincastTestingPostgres spincastTestingPostgres;
@Inject
private DataSource testDataSource;
The standalone Postgres database will then be started automatically when your tests are started.
When the tests are over, you can stop Postgres:
@Override
public void afterClass() {
super.afterClass();
spincastTestingPostgres.stopPostgres();
}
You can change some configurations used the database by binding a custom implementation
of the SpincastTestingPostgresConfig interface.
If you don't, the default configurations
will be used.
{#==========================================
Testing a real .jar
==========================================#}
Testing code inside a .jar file
Sometimes, you need to test code exactly as it will be run in production, which means
from within an executable .jar file. Your Spincast application would indeed run from a
standalone Fat Jar when deployed to production... And tests executed from an IDE don't always have the
same behavior than code running from a .jar file.
Indeed, if you run your tests from an IDE (or using the command line), all the classpath resources
would be located on the file system, as regular files. But, in production, those resources
will be embedded in your .jar file. Accessing and using those resources, from the file system
or from inside a .jar file, may be very different. So how can you run tests in a way that
the code to validate is located inside a .jar file?
The answer is that Spincast provides utilities to extract a test Maven project from the classpath to the file system,
to programmatically run the "package" Maven goal on this extracted project and then to run
the .jar file generated from this process in order to test the code located inside it!
In more details:
-
You need to install the Spincast Process Utils plugin.
-
You create a Maven project containing the code you want to test from within a .jar file. You save this project
in your application's resources folder ("src/main/resources/testMavenProject" for example).
Here's an example
of such Maven project.
-
In one of your @Test, you use the "Running a goal on an external Maven project"
feature provided by the
Spincast Process Utils plugin
to programmatically package this project:
File extractedProjectDir =
getSpincastProcessUtils()
.executeGoalOnExternalMavenProject(new ResourceInfo("/testMavenProject", true),
MavenProjectGoal.PACKAGE);
This will automatically extract the project from the classpath to the file system and will
generate the .jar
containing the code to test! This .jar file will be generated at
"${extractedProjectDir}/target/my-test-project-1.0.0.jar" for example,
depending on the name and version of the project's artifact.
Note that the temporary directory where the
project is extracted on the file system is returned by the executeGoalOnExternalMavenProject(...)
method.
-
You use another feature provided by the
Spincast Process Utils plugin
,
"Executing an external program, asynchronously"
to execute the generated .jar file. For example:
ProcessExecutionHandlerDefault handler = new ProcessExecutionHandlerDefault();
getSpincastProcessUtils().executeAsync(handler,
"java",
"-jar",
generatedJarFilePath,
"12345");
try {
// Wait for the HTTP port to be open
handler.waitForPortOpen("localhost", 12345, 10, 1000);
HttpResponse response = getHttpClient().GET("http://localhost:12345/test")
.send();
assertEquals(HttpStatus.SC_OK, response.getStatus());
} finally {
handler.killProcess();
}
In this example, the generated .jar file containing the code we want to test starts an HTTP server
(the test Maven project is, in fact, a standalone Spincast application!)...
We wait for the port this server is started on to be available and we then send a request
to it.
For your @Test to know if the executed code worked successfully or not inside the .jar file, you can
make the endpoint of your HTTP server return a 200
status code, for example. You could also return
a JSON
object containing more details about the result of the execution.
-
Finally, when your test is done, you kill the created process ("
handler.killProcess()
").
If you need to tweak the code of the test project before packaging it, or if you want to specify where
on the file system the project should be extracted, you can:
-
Extract the project from the classpath to the file system by yourself using
SpincastUtils#copyClasspathDirToFileSystem(...).
-
Tweak the content of the extracted project, as you wish.
-
And then call SpincastProcessUtils#executeGoalOnExternalMavenProject(...)
to compile/package/install it.
Note that when using a test Maven project, and that Maven project uses artifacts from your
main multi-modules project, you may have to add those artifacts as
<scope>test</scope>
dependencies in your main artifact, where the test
Maven project is packaged. Indeed, without this, Maven can not know in advance that those artifacts are required by
the test Maven project, and therefore may not have built them prior to running the tests! By adding them as
dependencies in your main project, Maven will build those artifacts first.
Note that if you simply need to replace some placeholders
in the pom.xml
file of the project, the
(executeGoalOnExternalMavenProject(...)
method already provides a way of doing it.
Here's
a real test class
validating code located inside a .jar file.
{#==========================================
Post install tests
==========================================#}
Post install tests
In some cases, mainly if you have some tests that programmatically package a test Maven project
and then uses the generated .jar file (as seen in the previous section),
you may need those tests to be run only when the artifacts of your main project are available
in your local repository.
Indeed, such test Maven projects may use artifacts from your main
project (in their pom.xml
) and those artifacts may not be found if they were not
installed in the first place!
This situation may occur for example during the release of your project, if you use the "mvn release:prepare
"
command.
For such tests that need to be run at the Maven install
phase (right after
the default maven-install-plugin
plugin), you can suffix their names
with "PostInstallTest". For example, a test class named "ExamplePostInstallTest"
would not be run at the standard Maven test
phase, but rather at the
Maven install
phase!:
public class ExamplePostInstallTest extends NoAppTestingBase {
@Test
public void test() throws Exception {
//...
}
}