I'm running a jUnit 3 Testcase via jUnit4/Eclipse.
Here is my custom JUnit38ClassRunner:
public class CR extends JUnit38ClassRunner{...}
So I run my Testcase:
#RunWith(CR.class)
public class TC extends TestCase
{...}
Everything works fine...
Here is my Testsuite:
public class TS {
public static Test suite() {
TestSuite result = new TestSuite();
result.addTest(new TestSuite(TC.class));
return result;
} }
How can i achieve, that TC is running through my custom runner CR in this Testsuite?
Thanks
Related
To create the environment just once and to avoid inheritance I have defined a JUnit Suite class with a #ClassRule:
#RunWith(Suite.class)
#Suite.SuiteClasses({
SuiteTest1.class
})
public class JUnitTest {
#ClassRule
private static DockerComposeContainer env = ...
#BeforeClass
public static void init(){
...
}
...
}
And there's a Test class that uses env in a test method:
public class SuiteTest1 {
#Test
public void method(){
client.query(...);// Executes a query against docker container
}
}
When I execute the tests by running the Test Suite everything works as expected. But when I directly try to run (even with IDE) the SuiteTest1 test class, it fails and nothing from the Suite is called (i.e. #ClassRule and #BeforeClass).
Any suggestions on how to achieve also the SuiteTest1 single execution in an good way (without calling static methods of JUnitTest from within the SuiteTest1) ?
Rephrasing the question: you want a JUnit suite with before-all and after-all hooks, which would also run when running the tests one by one (e.g. from an IDE).
AFAIK JUnit 4 provides nothing out-of-the-box for this, but if you're OK with incorporating some Spring third-parties deps (spring-test and spring-context) into your project I can propose a workaround I've been using.
Full code example of what follows in this post can be found here.
Solution (using Spring)
We'll use Spring context for implementing our initialization and cleanup. Let's add a base class for our tests:
#ContextConfiguration(initializers = AbstractTestClass.ContextInitializer.class)
public class AbstractTestClass {
#ClassRule
public final static SpringClassRule springClassRule = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
public static class ContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext context) {
System.out.println("Initializing context");
context.addApplicationListener(
(ApplicationListener<ContextClosedEvent>)
contextClosedEvent ->
System.out.println("Closing context"));
}
}
}
Note the SpringClassRule and SpringMethodRule JUnit rules which enhance our base class with Spring-superpowers (Spring test annotation processing - ContextConfiguration in this case, but there are many more goodies in there - see Spring testing reference for details). You could use SpringRunner for this purpose, but it's a far less flexible solution (thus omitted).
Test classes:
public class TestClass1 extends AbstractTestClass {
#Test
public void test() {
System.out.println("TestClass1 test");
}
}
public class TestClass2 extends AbstractTestClass {
#Test
public void test() {
System.out.println("TestClass2 test");
}
}
And the test suite:
#RunWith(Suite.class)
#SuiteClasses({TestClass1.class, TestClass2.class})
public class TestSuite {
}
Output when running the suite (removed Spring-specific logs for brievity):
Initializing context
TestClass1 test
TestClass2 test
Closing context
Output when running a single test (TestClass1):
Initializing context
TestClass1 test
Closing context
A word of explanation
The way this works is because of Spring's context caching. Quote from the docs:
Once the TestContext framework loads an ApplicationContext (or WebApplicationContext) for a test, that context is cached and reused for all subsequent tests that declare the same unique context configuration within the same test suite. To understand how caching works, it is important to understand what is meant by “unique” and “test suite.”
-- https://docs.spring.io/spring/docs/5.1.2.RELEASE/spring-framework-reference/testing.html#testcontext-ctx-management-caching
Beware that you will get another context (and another initialization) if you override the context configuration (e.g. add another context initializer with ContextConfiguration) for any of the classes in the hierarchy (TestClass1 or TestClass2 in our example).
Using beans to share instances
You can define beans in your context. They'll be shared across all tests using the same context. This can be useful for sharing an object across the test suite (a Testcontainers container in your case judging by the tags).
Let's add a bean:
#ContextConfiguration(initializers = AbstractTestClass.ContextInitializer.class)
public class AbstractTestClass {
#ClassRule
public final static SpringClassRule springClassRule = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
public static class ContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext context) {
ADockerContainer aDockerContainer = new ADockerContainer();
aDockerContainer.start();
context.getBeanFactory().registerResolvableDependency(
ADockerContainer.class, aDockerContainer);
context.addApplicationListener(
(ApplicationListener<ContextClosedEvent>)
contextClosedEvent ->
aDockerContainer.stop());
}
}
}
And inject it into the test classes:
public class TestClass1 extends AbstractTestClass {
#Autowired
private ADockerContainer aDockerContainer;
#Test
public void test() {
System.out.println("TestClass1 test " + aDockerContainer.getData());
}
}
public class TestClass2 extends AbstractTestClass {
#Autowired
private ADockerContainer aDockerContainer;
#Test
public void test() {
System.out.println("TestClass2 test " + aDockerContainer.getData());
}
}
ADockerContainer class:
public class ADockerContainer {
private UUID data;
public void start() {
System.out.println("Start container");
data = UUID.randomUUID();
}
public void stop() {
System.out.println("Stop container");
}
public String getData() {
return data.toString();
}
}
(Example) output:
Start container
TestClass1 test 56ead80b-ec34-4dd6-9c0d-d6f07a4eb0d8
TestClass2 test 56ead80b-ec34-4dd6-9c0d-d6f07a4eb0d8
Stop container
I'm trying to use JUnit for my functional testing. Basically I'm doing this to have access to the JUnit reports. Unfortunately I am running into a problem when trying to launch JUnit from a main method.
Basically I am developing a functional testing tool where the user can provide a test filename as a parameter from the command line. I've simplified it a bit below:
import org.junit.runner.JUnitCore;
public class MainClass {
public static void main(String[] args) throws Exception {
TestCase testCase = new TestCase() {
#Override
public String getPath() {
return args[0];
}
};
JUnitCore junit = new JUnitCore();
junit.run(testCase.getClass());
}
}
The TestCase class then acts on the supplied parameter and provides output:
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestCase {
private static final Logger LOGGER = LoggerFactory.getLogger(TestCase.class);
public String getPath() {
return "etc/Default.flow";
}
#Test
public void testFunc() {
try {
LOGGER.info("Entered testFunc()");
Launcher launcher = new Launcher(getPath());
launcher.launch();
launcher.awaitCompletion();
Assert.assertTrue(launcher.getStatus());
LOGGER.info("Success");
} catch (AssertionError e) {
LOGGER.error("Assertion error", e);
}
}
So from the above, we see that the Launcher instance will be launched with a different filename depending on what was entered on the command line.
The problem is however that Junit is not running my anonymous class. Basically the main method exits without any of the assertions or logging taking place. The TestCase testFunc() method is therefore not called at all.
However, when I change the TestCase instance to not be anonymous, everthing works as expected and the testcase is successful:
import org.junit.runner.JUnitCore;
public class MainClass {
public static void main(String[] args) throws Exception {
TestCase testCase = new TestCase();
JUnitCore junit = new JUnitCore();
junit.run(testCase.getClass());
}
}
Why would JUnit launch the Test class only when it is not anonymous?
If you add listener junit.addListener(new TextListener(System.out)); before running test you will see something like:
There were 2 failures:
1) initializationError(junit.MainClass$1)
java.lang.Exception: The class junit.MainClass$1 is not public.
...
2) initializationError(junit.MainClass$1)
java.lang.Exception: Test class should have exactly one public constructor
at org.junit.runners.BlockJUnit4ClassRunner.validateOnlyOneConstructor(BlockJUnit4ClassRunner.java:158)
at org.junit.runners.BlockJUnit4ClassRunner.validateConstructor(BlockJUnit4ClassRunner.java:147)
at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:127)
at org.junit.runners.ParentRunner.validate(ParentRunner.java:416)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:84)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:65)
It means that JUnit is unable to execute test cases represented by anonymous classes.
I can use Arquillian TestRunner JUnit Container to write sequential tests.
import org.jboss.arquillian.junit.InSequence;
import org.jboss.arquillian.junit.Arquillian;
#RunWith(Arquillian.class)
public class ClassToTest{
#Test
#InSequence(1)
public void test1() {
// test something (1)
}
#Test
#InSequence(2)
public void test2() {
// test something (2)
}
}
It is possible to do same thing using Arquillian TestRunner TestNG Container? If so how can I do that.
Yes. You can do the sequencing of test methods by dependency chaining in TestNG.
it would be like the below
#Test
public void test1() {
// test something (1)
}
#Test(dependsOnMethods = { "test1" })
public void test2() {
// test something (2)
}
Please refer the below for more info
http://www.tutorialspoint.com/testng/testng_dependency_test.htm
I have few JUnit Tests and I want to decide which one to use at runtime. I checked previous answers at SO and I ended up creating Test Suite dynamically.
This class is where my application starts. I have CustomTestSuite class and Main class adds Tests to my custom suite.
public class Main {
public static junit.framework.TestSuite suite()
{
CustomTestSuite suite = new CustomTestSuite();
suite.addTest(new JUnit4TestAdapter(BTest.class));
suite.addTest(new JUnit4TestAdapter(ATest.class));
return suite;
}
}
CustomTestSuite.java
public class CustomTestSuite extends TestSuite {
#BeforeClass
public static void setUp() throws Exception {
System.out.println("Before class test");
}
#After
public void tearDown() throws Exception {
System.out.println("After class test");
}
}
My ATest and BTest are simple Test classes, I will just show ATest as sample:
public class ATest{
#Test
public void testMethod() {
System.out.println("testMethod");
}
}
When I start running my project from Main class, it is expected to run the method with #BeforeClass first, do testing, and then run the method with #AfterClass annotation.
Tests are working fine but it skips setUp method and tearDown method. I tried #Before and #BeforeClass annotations both.
I am confused with suite structure. Any help would be appreciated.
Thanks
#Before and #BeforeClass are supposed to be used in Test class not in TestSuite. If need to have common setUp and tearDown for more than one Test class, then put those both methods in a super class and extend that super by ATest and BTest test classes. And also the Suite can be built and run simply with #RunWith and #SuiteClasses annotations and the CustomTestSuite class is not needed.
So the changes are as below.
The CustomTestSuite becomes TestSuper
public class TestSuper {
#BeforeClass
public static void setUp() throws Exception {
System.out.println("Before class test");
}
#After
public void tearDown() throws Exception {
System.out.println("After class test");
}
}
Now the ATest extends TestSuper
public class ATest extends TestSuper {
#Test
public void testMethod() {
System.out.println("testMethod");
}
}
Similarly BTest also should extend TestSuper.
Simply add #RunWith and #SuiteClasses annotations to Main class as below and run Main.
#RunWith(Suite.class)
#SuiteClasses({ATest.class, BTest.class})
public class Main {
}
Have a go with these changes.
I want to add testfiles to a testsuite at runtime and my test files are not extending to Testcase as i am using junit 4.11.
Below is the code:
#RunWith(org.junit.runners.AllTests.class)
class MasterTester extends TestCase{
public static TestSuite suite1() {
TestSuite suite = new TestSuite();
for(Class<? extends TestCase> klass : gatherTestClasses()) {
suite.addTestSuite(klass);
}
return suite;
}
private static Class<?> gatherTestClasses()
{
return AbcIT.class;//getting a compile time error
}
}
I am getting a compile time error saying class of type cannot be added to class
Please suggest?
Perhaps have a look at #Andrejs answer over here as he mentions dynamically adding JUnit 4 testcases to a testsuite:
#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;
}
}