Create JUnit TestSuite in a non-static way - java

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;
}
}

Related

Spring Boot / JUnit, run all unit-tests for multiple profiles

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.

Dynamically Creating JUnit4 Test Suite from Properties File

The solution I am using to create a JUnit test suite dynamically can be found in this similar question here: How do I Dynamically create a Test Suite in JUnit 4?
The solution I am trying to adapt looks like such:
#RunWith(AllTests.class)
public class SomeTests
{
public static TestSuite suite()
{
TestSuite suite = new TestSuite();
suite.addTest(new JUnit4TestAdapter(Test1.class));
suite.addTest(new JUnit4TestAdapter(Test2.class));
return suite;
}
}
However, I would not only like to be able to dynamically create a test suite, but also be able to allow for the user running my program to specify which tests they would like to run using a properties file.
Is there a way I can annotate my classes with a String such that I can get the actual class type given the annotation String? Are there any viable solutions for this or is it just bad practice in general?
As I understand you would like to mark your test classes as belonging to one or more groups, then user defines the group of test cases to execute. Is it correct?
Bad or good this practice is, it is already implemented in TestNG. There is no such feature in JUnit. But you could easily add annotation scanner to your code and select proper test classes dynamically (e.g. by using https://github.com/ronmamo/reflections to collect all your annotated tests in class path with just single line of code).

Using PowerMock with Cucumber

I've written a JUnit test that uses Mockito and PowerMock to mock some classes. I'm trying to convert it a Cucumber test, but the static PowerMock features don't work.
Extracts of the two relevant Cucumber classes:
Runner
#RunWith(Cucumber.class)
public class JWTValidatorBDDTest {
}
Steps Class
public class JWTValidatorCukeTest {
String tokenValue;
JWTValidator jwtValidator;
MockHttpServletRequest mockRequest;
#Before
public void before() throws IOException {
this.mockRequest = new MockHttpServletRequest();
PowerMockito.mockStatic(JWTAuthConnectionManager.class);
BDDMockito.given(JWTAuthConnectionManager.postToken(anyString(), anyString(), anyString())).willReturn(200);
Mockito.doReturn(200).when(JWTAuthConnectionManager.postToken(anyString(), anyString(), anyString()));
}
#Given("^a JWT token with the value (.*)")
public void a_JWT_token_with_the_value_(String token) {
this.jwtValidator = new JWTValidator("https://test.7uj67hgfh.com/openam", "Authorization", "Bearer");
this.tokenValue = token;
}
Whilst this code works within the JUnit test, it fails here - it enters the JWTAuthConnectionManager.postToken() method that should be mocked and then fails by executing code within there. I've tried adding the lines:
#RunWith(PowerMockRunner.class)
#PrepareForTest(JWTAuthConnectionManager.class)
to both of the above classes (although of course I can't use RunWith in the Runner class as it already has one RunWith annotation), but this doesn't change anything.
How do I get PowerMock to work within Cucumber?
Seems like it is possible now with #PowerMockRunnerDelegate annotation. I use #RunWith(PowerMockRunner.class) and #PowerMockRunnerDelegate(Cucumber.class) and it's working. Taken an advise from here: https://medium.com/#WZNote/how-to-make-spock-and-powermock-work-together-a1889e9c5692
Since version 1.6.0 PowerMock has support for delegating the test execution to another JUnit runner without using a JUnit Rule. This leaves the actual test-execution to another runner of your choice. For example tests can delegate to “SpringJUnit4ClassRunner”, “Parameterized” or the “Enclosed” runner.
There are also options of using #Rule: PowerMockRule rule = new PowerMockRule(); instead of #RunWith(PowerMockRunner.class) (so Runner can be something else) - but the comment by Stefan Birkner suggests that Cucumber runner should support rules to use this and I am not sure if it does (now).
Hope it helps someone.
You can't use the PowerMockRunner because a test can only have one runner (in your case Cucumber). But AFAIK you can use the PowerMockRule instead of the PowerMockRunner.

Using TestNG, is there a way to ignore #before class when calling one class into another?

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

How can I run a (JUnit) TestSuite created by a factory method?

I was looking for a verification test for custom implemented collections, and stumbled upon this: http://www.gamlor.info/wordpress/2012/09/google-guava-collection-test-suite/
I haven't used junit before (so I'm a total noob with junit). I added junit4 to my test project and... got stuck on how to actually run the test suite created by the Google Guava Collection Test Suite. I run annotated test from my test class just fine, but not the test suite from guava.
The junit docs say that suites are created by annotating a suite class with the Suite annotation, listing the cases they should include, but obviously I can't list a dynamically generated class that way. I would be happy to just create a simple test and run the entire suite as a single test, only... how do I get junit to run the suite instance?
If you have a factory method that returns a Test object (let's call it TestMaker.foo(), then you can write something like the following to take the Test and add it to your own TestSuite class:
import junit.framework.JUnit4TestAdapter;
import junit.framework.TestSuite;
import org.junit.runner.RunWith;
import org.junit.runners.AllTests;
#RunWith(AllTests.class)
public class TestRunner {
public static TestSuite suite() {
TestSuite ts = new TestSuite();
ts.addTest(TestMaker.foo());
return ts;
}
}
Now, when you run the TestRunner tests, it will also run the Test returned by TestMaker.foo() along with any other tests that might be defined directly in TestRunner.
For related discussion (for example, how to refer to a Test Class rather than pass a Test object), check out: How do I Dynamically create a Test Suite in JUnit 4?

Categories