How to make a common #Testcontainer for multiple Jupiter tests? - java

I have an abstract controller test class and its inheritor with units, but I want to separate tests into different classes according to the controller method they are testing. Every time I create the second test-class and put a test in it I get the following error:
Failed to validate connection org.postgresql.jdbc.PgConnection#28806954 (This connection has been closed.). Possibly consider using a shorter maxLifetime value.
I have the following base class:
#SpringBootTest
#AutoConfigureMockMvc
#Testcontainers
public abstract class ControllerAbstractTest {
#Container
private final static PostgreSQLContainer postgreSQLContainer;
static {
postgreSQLContainer = new PostgreSQLContainer<>("postgres:13")
.withDatabaseName("my-test-db")
.withUsername("a")
.withPassword("a");
postgreSQLContainer.start();
System.setProperty("spring.datasource.url", postgreSQLContainer.getJdbcUrl());
System.setProperty("spring.datasource.password", postgreSQLContainer.getPassword());
System.setProperty("spring.datasource.username", postgreSQLContainer.getUsername());
}
// other methods
Tests work just fine in a single inheritor class.
I am using org.testcontainers:junit-jupiter:1.16.2, same version for postgresql and spring boot 2.5.6. #Test annotation is from org.junit.jupiter.api.Test
I have tried adding #Testcontainers to inheritors and removing it from the base test class, but it did not help.

I prefer to start a container in a separate configuration so the test classes are not required to extend a specific abstract class.
/**
* Starts a database server in a local Docker container.
*/
#TestConfiguration
public class TestDatabaseConfiguration {
private static final PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer<>("postgres:13")
.withDatabaseName("my-test-db")
.withUsername("username")
.withPassword("password");
static {
postgreSQLContainer.start();
System.setProperty("spring.datasource.url", postgreSQLContainer.getJdbcUrl());
System.setProperty("spring.datasource.password", postgreSQLContainer.getPassword());
System.setProperty("spring.datasource.username", postgreSQLContainer.getUsername());
}
}
Test classes that want to connect to the single shared database server are annotated with:
#Import(TestDatabaseConfiguration.class)

Related

JUnit: is it possible to create a Test Suite that executes all test of classes that share a naming convention?

I am aware that I can make a TestSuite enumerating all the classes that I want, for example:
#RunWith(Suite.class)
#SuiteClasses({SQLServerTests1.class, SQLServerTest2.class, ... })
public class AllSQLServerTests {}
However I have almost 100+ classes and I don't want to have to remember to include any new one in the #SuiteClasses annotation.
As my classes have a naming convention (starting with "SQLServer" for example) I am searching for a way to do something like this:
#RunWith(Suite.class)
#SuiteClasses(prefix="SQLServer")
public class AllSQLServerTests {}
is it possible with plain JUnit? with spring or any other framework?
Tag'em
You can add many tags to each test or test class:
#Test
#Tag("red")
#Tag("production")
public void testWithColour() {...}
#RunWith(JUnitPlatform.class)
#IncludeTags("red & !production")
public class JUnit5Example {
//...
}
You can also use #ExcludeTags but it cannot co-exist with #IncludeTags
Run all in test package
#RunWith(JUnitPlatform.class)
#SelectPackages("com.acme.megaproduct.slowtests")
public class JUnit5Example {
//...
}
Write custom Test Runner
Perhaps none of the above can acommodate your needs, in which case you can add custom filtering by writing your own runner.
See here for step by step how to do it.
Then you just use it like:
#RunWith(MyCustomRunner.class)
public class CustomTestSuite {
//...
}

How can I use google guice DI outside of testNG test classes in a testNG based framework?

it is very simple to implement injection of objects into a testNG test class, it is handled mostly for us, however how can I build google guice DI into my framework and use it for classes which are not necessarily tests?
I want to inject using simple dependency injection for dependencies of my Page Object classes, these are nothing really to do with testNG, so how can we get the dependencies initialized for those?
Here is a simple example piece of code I want to replace:
public class HeaderComponent extends AbstractBasePageObject {
private static final Logger LOG = LoggerFactory.getLogger(HeaderComponent.class);
private MenuComponent menu = new MenuComponent(getDriver());
public HeaderComponent(NgWebDriver ngdriver) {
super(ngdriver);
}
public MenuComponent getMenuComponent() {
return menu;
}
}
This class is absolutely nothing to do with testNG itself, so how can I initialize everything for the outcome of:
#Inject
MenuComponent menu
Everything I try the menu throws a nullPointerException because I am having trouble having guice somewhat loaded I think.
I have create some general example for you - test with injection example
It works as you're expecting, I hope. It provides some test configs, injects them to driver and at last driver is injected in test component.
Result test looks like:
import com.google.inject.Inject;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
#Guice(modules = {TestModule.class})
public class SimpleTest {
#Inject
ComponentUnderTest component;
#Test
public void sampleTest() {
System.out.println(component.getParamToTest());
System.out.println(component.param);
System.out.println(component.elseone);
}
}

Get top-most executing TestSuite in JUnit

I need to know the suite class that included the currently running JUnit test. For example, if you have
#SuiteClasses({SubSuite.class})
class ParentSuite { }
#SuiteClasses({TestCase.class})
class SubSuite { }
class TestCase {
#Test
public void testMethod() { }
}
and execute ParentSuite with JUnit, then I want to get a reference to ParentSuite.class. Is this possible?
There is the TestWatcher rule that gets you an instance of Description, which is kind of in the right direction, but that does not include the suite class.
I know this is probably not the best way to write unit tests. My original problem is to run a validation on all classes that are in the project under test, but not those of the dependencies. The TestCase will be in a dependency and included by test suites in other projects. The only solution I could think of is filter those classes with the same source location as that of the top-most-suite. To make that more clear:
BaseLibrary
* contains TestCase and TestSuite
* has classes that should not be validated
ConsumerProject
* has a test-scoped and test-classified dependency to BaseLibrary
* contains ParentSuite
* has classes that should be validated
You probably want to use JUnit #Category https://github.com/junit-team/junit/wiki/Categories
Here's a blog on how to make Categories https://weblogs.java.net/blog/johnsmart/archive/2010/04/25/grouping-tests-using-junit-categories-0
This way you can make Categories for each of your projects.
public interface ConsumerProject {}
Then you can use the #Category annotation to mark test classes (or even test methods) as being in particular categories:
#Category(ConsumerProject.class)
public class TestCase { ... }
Then your suites can be set up to run all the tests for particular categories
#RunWith(Categories.class)
#IncludeCategory(ConsumerProject.class)
#SuiteClasses( { ....})
public class ConsumerProjectSuite { }
You can even have the same test get marked with multiple categories
#Category({ConsumerProject.class, OtherProject.class})
public class CommonTests { }

Share object reference between different JUnit tests

I have a couple of JUnit tests which need a reference for a expensive resource (a WALA class hierachie), which needs about 30s to be created. I would like to share this reference in my whole test suite.
I thought about a static member in a base class which is laziely initiated with a #BeforeClass method. After test is run the JVM should be determined anyway.
Is there any other way to accomplish this? Or any other best practice?
Create an explicit test suite (cf. this answer) to run these tests, and use #BeforeClass and #AfterClass on the suite itself (cf. this answer):
#RunWith(Suite.class)
#Suite.SuiteClasses({Test1.class, Test2.class})
public class MySuite {
#BeforeClass
public static void initResource() {
MyExpensiveResource.init();
}
#AfterClass
public static void disposeResource() {
MyExpensiveResource.dispose();
}
}

Junit SuiteClasses with a static list of classes

SuiteClasses will work just fine with a list of classes like {Test1.class,Test2.class}, but when I try to generate a static list of classes, it says incompatible types: required java.lang.Class<?> but found java.lang.Class<?>[]
What am I missing?
#RunWith(Suite.class)
#Suite.SuiteClasses(TestSuite.classes)
public class TestSuite {
public static Class<?> [] classes;
static {
classes = new Class<?> [1];
classes[0] = MyTest.class;
}
}
That shouldn't really work. You are intended to put the array within the annotation as a constant. Even if you got past this problem, the compiler would reject it. What you need to do is this:
#RunWith(Suite.class)
#Suite.SuiteClasses({MyTest.class, MyOtherTest.class})
public static class TestSuite {
}
Note the squiggly brackets.
I'm sure what you are trying to get at is to be able to build the list of classes in the suite dynamically.
I submitted a request to them to allow that, but in the mean time the only way to do it is to subclass the Suite class like so:
public class DynamicSuite extends Suite {
public DynamicSuite(Class<?> setupClass) throws InitializationError {
super(setupClass, DynamicSuiteBuilder.suite());
}
}
#RunWith(DynamicSuite.class)
public class DynamicSuiteBuilder {
public static Class[] suite() {
//Generate class array here.
}
}
#SuiteClasses is a class annotation defined in JUnit 4.4 in org.junit.runners.Suite.SuiteClasses. It allows you to define a suite class as described in the previous question.
By the way, the API document of JUnit 4.4 has a major typo for the org.junit.runners.Suite class (Suite.html).
Using Suite as a runner allows you to manually build a suite containing tests from many classes. It is the JUnit 4 equivalent of the JUnit 3.8.x static Test suite() method. To use it, annotate a class with #RunWith(Suite.class) and #SuiteClasses(TestClass1.class, ...). When you run this class, it will run all the tests in all the suite classes.
#SuiteClasses(TestClass1.class, ...) should be changed to #Suite.SuiteClasses({TestClass1.class, ...}).
Someone provided wrong information on build test suite in JUnit 4.4. Do not follow this:
JUnit provides tools to define the suite to be run and to display its results. To run tests and see the results on the console, run:
org.junit.runner.TextListener.run(TestClass1.class, ...);

Categories

Resources