I have a BaseTest class which consists of several tests. Each test shall be executed for EVERY profile I list.
I thought about using Parameterized values such as:
#RunWith(Parameterized.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
// #ActiveProfiles("h2-test") // <-- how to iterate over this?
public abstract class BaseTest {
#Autowired
private TestRepository test;
// to be used with Parameterized/Spring
private TestContextManager testContextManager;
public BaseTest(String profile) {
System.setProperty("spring.profiles.active", profile);
// TODO what now?
}
#Parameterized.Parameters
public static Collection<Object[]> data() {
Collection<Object[]> params = new ArrayList<>();
params.add(new Object[] {"h2-test" });
params.add(new Object[] {"mysql-test" });
return params;
}
#Before
public void setUp() throws Exception {
this.testContextManager = new TestContextManager(getClass());
this.testContextManager.prepareTestInstance(this);
// maybe I can spinup Spring here with my profile?
}
#Test
public void testRepository() {
Assert.assertTrue(test.exists("foo"))
}
How would I tell Spring to run each test with these different profiles? In fact, each profile will talk to different datasources (in-memory h2, external mysql, external oracle, ..) so my repository/datasource has to be reinitialized.
I know that I can specify #ActiveProfiles(...) and I can even extend from BaseTest and override the ActiveProfile annotation. Although this will work, I only show a portion of my test-suite. Lots of my test-classes extend from BaseTest and I don't want to create several different profile-stubs for each class. Currently working, but ugly solution:
BaseTest (#ActiveProfiles("mysql"))
FooClassMySQL(annotation from BaseTest)
FooClassH2(#ActiveProfiles("h2"))
BarClassMySQL(annotation from BaseTest)
BarClassH2(#ActiveProfiles("h2"))
Thanks
For what it's worth:
My use case was to run a specific test class for multiple spring profiles, this is how I achieved it:
#SpringBootTest
abstract class BaseTest {
#Test void doSomeTest() {... ARRANGE-ACT-ASSERT ...}
}
#ActiveProfiles("NextGen")
class NextGenTest extends BaseTest {}
#ActiveProfiles("Legacy")
class LegacyTest extends BaseTest {}
If you use Maven you can actually specify active profile from command line (or env variable if needed):
mvn clean test -Dspring.profiles.active=h2-test
The approach with parameterized test may not work in this case, because profile has to be specified before Spring boots up its context. In this case when you run parameterized integration test the context will be already booted up before test runner starts running your test. Also JUnit's parameterized tests were invented for other reasons (running unit tests with different data series).
EDIT: Also one more thing - when you decide to use #RunWith(Parameterized.class) you wont be able to use different runner. In many cases (if not all if it comes to integration testing) you want to specify different runner, like SpringRunner.class - with parameterized test you wont be able to do it.
Spring profiles are not designed to work in this way.
In your case, each profile uses a specific datasource.
So each one requires a Spring Boot load to run tests with the expected datasource.
In fact, what you want to do is like making as many Maven build as Spring profiles that you want to test.
Besides, builds in local env should be as fast as possible.
Multiplying automated tests execution by DBMS implementation that requires a Spring Boot reload for each one will not help.
You should not need to specify #ActiveProfiles .
It looks rather like a task for a Continuous Integration tool where you could define a job that executes (sequentially or parallely) each Maven build by specifying a specific Spring Boot profile :
mvn clean test -Dspring.profiles.active=h2
mvn clean test -Dspring.profiles.active=mysql
etc...
You can also try to perform it in local by writing a script that performs the execution of the maven builds.
But as said, it will slowdown your local build and also complex it.
Related
A set of tests should be run on every microservice. Current solution is to have an abstract class and extend in every service, providing the necessary properties in abstract getters.
public abstract class AbstractTest {
#LocalServerPort
protected int serverPort;
protected abstract String getPath();
#Test
void someTest() {}
#Test
void conditionalTest() {}
}
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
classes = {...})
#ActiveProfiles(...) // etc
public class MyTest extends AbstractTest {
// ... implement getPath()
// tests from parent will be executed
}
The goal:
Ditch inheritance and have the AbstractTest's logic get executed automatically with conditional #Test execution based on beans/properties etc.
The possible solution:
A concrete class with all the tests or some sort of Configuration/TestFactory to create the necessary tests. It should take into account available properties and beans to determine which tests to run.
The problem:
How can those tests (created in runtime) be discovered and registered for execution?
How to inject all the properties that are part of the current context of the #SpringBootTest?
Failed attempts:
TestInstanceFactory extension doesn't seem to be the solution as it requires an instance of the class which it annotates.
Using the Launcher API seems overkill, and also doesn't seem to work, since the library class won't be created with the Spring context configs.
using cglib and a base class Spring Contract-style is not a desirable solution
Ideally I don't want the client of this lib to implement/create anything, so abstract String getPath(); would be a test.lib.path property, and if it's present, a test from the library which uses it will run.
Any thoughts on this would be great, because right now this just seems impossible to me.
What is the reason to have the inheritance for tests?
In case you need to share some common logic within the tests you may try JUnit features (custom rules/extensions), for example
For junit < 5.x.x #Rule functionality https://junit.org/junit4/javadoc/4.12/org/junit/rules/TemporaryFolder.html https://stackoverflow.com/a/34608174/6916890
For junit >= 5.x.x (jupiter) there is an extension API
https://junit.org/junit5/docs/current/user-guide/#writing-tests-built-in-extensions-TempDirectory
When writing code that interacts with external resources (such as using a web service or other network operation), I often structure the classes so that it can also be "stubbed" using a file or some other input method. So then I end up using the stubbed implementation to test other parts of the system and then one or two tests that specifically test calling the web service.
The problem is I don't want to be calling these external services either from Jenkins or when I run all of the tests for my project (e.g. "gradle test"). Some of the services have side effects, or may not be accessible to all developers.
Right now I just uncomment and then re-comment the #Test annotation on these particular test methods to enable and disable them. Enable it, run it manually to check it, then remember to comment it out again.
// Uncomment to test external service manually
//#Test
public void testSomethingExternal() {
Is there is a better way of doing this?
EDIT: For manual unit testing, I use Eclipse and am able to just right-click on the test method and do Run As -> JUnit test. But that doesn't work without the (uncommented) annotation.
I recommend using junit categories. See this blog for details : https://community.oracle.com/blogs/johnsmart/2010/04/25/grouping-tests-using-junit-categories-0.
Basically, you can annotate some tests as being in a special category and then you can set up a two test suites : one that runs the tests of that category and one that ignores tests in that category (but runs everything else)
#Category(IntegrationTests.class)
public class AccountIntegrationTest {
#Test
public void thisTestWillTakeSomeTime() {
...
}
#Test
public void thisTestWillTakeEvenLonger() {
....
}
}
you can even annotate individual tests"
public class AccountTest {
#Test
#Category(IntegrationTests.class)
public void thisTestWillTakeSomeTime() {
...
}
Anytime I see something manually getting turned on or off I cringe.
As far as I can see you use gradle and API for JUnit says that annotation #Ignore disables test. I will add gradle task which will add #Ignore for those tests.
If you're just wanting to disable tests for functionality that hasn't been written yet or otherwise manually disable some tests temporarily, you can use #Ignore; the tests will be skipped but still noted in the report.
If you are wanting something like Spring Profiles, where you can define rulesets for which tests get run when, you should either split up your tests into separate test cases or use a Filter.
You can use #Ignore annotation to prevent them from running automatically during test. If required, you may trigger such Ignored tests manually.
#Test
public void wantedTest() {
return checkMyFunction(10);
}
#Ignore
#Test
public void unwantedTest() {
return checkMyFunction(11);
}
In the above example, unwantedTest will be excluded.
I have two test classes each containing a number of tests. I'd like to run both of these together without having to have the #BeforeClass setup method being ran both times. I am calling the classes like this:
public static void main(String[] args) {
TestListenerAdapter tla = new TestListenerAdapter();
TestNG testng = new TestNG();
testng.setTestClasses(new Class[] { TestClass1.class, TestClass2.class });
testng.addListener(tla);
testng.run();
}
The reason for this is because I have both of them calling in a pop up menu and only want to select the option one time. If this is unclear I will try to further explain.
I have a collection of individual tests across 5 classes. I want each class to be able to run separately, but I also want to make them run collectively should I desire. In the #BeforeClass I have each of them calling another class that will select what URL I want to use (I am testing with TestNG and using Selenium WebDriver).
When this code runs it will execute the #BeforeClass in each class I list, and I would like to, if possible, ignore the #BeforeClass in all the tests if I execute the tests using the code above.
I would recommend passing a transformer in to your TestNG test case that implements, IAnnotationTransformer2. That transformer can allow you to control the behavior of the non #Test Annotations at runtime.
IAnnotationTransformer2
You can use a #BeforeTest in a common class of your 2 test classes.
I understand you want to run the stuff inside #Before only once for your 2 test classes that will be executed at same time together.
If you are using maven + junit 4.x, there is an option for setup things before and after test suit start and complete.
Or you can simply create a #ClassRule at suite level, please see the doc
I have a series of unit test where I need to clear a neo4j database. All the tests pass if I run them individually but when I run them all then some fail saying that a particular node could not be found:
org.neo4j.graphdb.NotFoundException: Node[6] not found.
at org.neo4j.kernel.impl.core.NodeManager.getNodeForProxy(NodeManager.java:505)
at org.neo4j.kernel.impl.core.NodeProxy.hasProperty(NodeProxy.java:151)
at org.springframework.data.neo4j.fieldaccess.PropertyFieldAccessorFactory$PropertyFieldAccessor.doGetValue(PropertyFieldAccessorFactory.java:85)
at org.springframework.data.neo4j.fieldaccess.ConvertingNodePropertyFieldAccessorFactory$ConvertingNodePropertyFieldAccessor.doGetValue(ConvertingNodePropertyFieldAccessorFactory.java:89)
at org.springframework.data.neo4j.fieldaccess.PropertyFieldAccessorFactory$PropertyFieldAccessor.getValue(PropertyFieldAccessorFactory.java:80)
at org.springframework.data.neo4j.fieldaccess.DefaultEntityState.getValue(DefaultEntityState.java:97)
at org.springframework.data.neo4j.fieldaccess.DetachedEntityState.getValue(DetachedEntityState.java:100)
at org.springframework.data.neo4j.fieldaccess.DetachedEntityState.getValue(DetachedEntityState.java:105)
I have tried this but it didn't solve my problem: Neo4jDatabaseCleaner
What's noticeable is that the tests which have the problem are the one with a relation with properties.
What else could I try?
What about using the ImpermanentGraphDatabase that comes with the Neo4j kernel?
Build/destroy the graph without worrying about cleaning up, etc.
The way we solve this is by having a context aware abstract class that all unit test classes extend. This method contains a before method that clears our all the data in all defined graph repositories.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/applicationContext.xml", "/applicationContext-test.xml" })
public abstract class AbstractTestBase {
#Autowired
private ApplicationContext ctx;
#Before
public void clearAllGraphRepositories() {
Map<String, GraphRepository> graphRepositories = ctx.getBeansOfType(GraphRepository.class);
for (GraphRepository graphRepository : graphRepositories.values()) {
graphRepository.deleteAll();
}
}
}
This can obviously easily be modified to only clear specific repositories, but I'll leave that to you... :-)
One easy way to do this is to run the test trantransactional and roll back after each test?
i'm using this tutorial to set up a test environment:
http://blog.everymansoftware.com/2011/11/development-setup-for-neo4j-and-php.html
the key point is a plugin for neo4j called test-delete-db-extension-1.8.jar
or, in gremlin, you can invoke the command g.clear(); (seems to be the same functionality as the plugins').
I am seeking for a way to create and let run a JUnit TestSuite in a non-static fashion.
Currently I am doing something like this:
public class MyTestSuite {
public static TestSuite suite() {
TestSuite suite = new TestSuite();
suite.addTest(...);
suite.addTest(...);
// ....
return suite;
}
}
I am doing this because I am creating the TestCases I am adding to the suite programmatically.
With this solution I am facing the problem that my class MyTestSuite is never instantiated. I would like to wire it with a spring container, e.g. using
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={...})
#Transactional
but I see no way of telling the SpringJUnit4ClassRunner that it should also execute my programmatic tests.
Thanks for your help!
Erik
Why use a suite at all? Seems simpler to put your tests in their own subdirectory and have an ant (or whatever build tool you're using) target that runs just the tests found there.
You could try and have MyTestSuite as part of your spring context (the test context) and fire an init method on it which would add your programmatic tests. That would allow you to inject MyTestSuite which has this programmtic tests added when it is instantiated by spring.
Hope that helps.
For JUnit3-style suite methods, JUnit does not create an instance of the class; it calls the method and calls run(TestResult) on the returned object.
SpringJUnit4ClassRunner is a JUnit4 Runner class, so it cannot be used to affect the behavior of JUnit3-style test suites. Spring does not provide a JUnit4-style suite implementation. If you want each of the test cases to use SpringJUnit4ClassRunner, your best option is to upgrade them to JUnit4.
If you are asking how you add your Spring tests to MyTestSuite:
public class MyTestSuite {
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(...);
suite.addTest(...);
suite.addTest(new JUnit4TestAdapter(ExampleSpringTest.class));
// ....
return suite;
}
}