I have a test case which has an #Autowired field. I would like to have one method for setting up the test case, as it has many #Test-annotated methods that will rely on the same generated data, (for which I need the autowired class).
What's a good way to achieve this?
If I have the #BeforeClass, then I need to make the method static, which breaks the autowiring.
1st solution
Use TestNG instead.
#Before* annotations behave this way in TestNG.
No method annotated with #Before* has to be static.
#org.testng.annotations.BeforeClass
public void setUpOnce() {
//I'm not static!
}
2nd solution
And if you don't want to do that, you can use an execution listener from Spring (AbstractTestExecutionListener).
You will have to annotate your test class like this:
#TestExecutionListeners({CustomTestExecutionListener.class})
public class Test {
//Some methods with #Test annotation.
}
And then implement CustomTestExecutionListener with this method:
public void beforeTestClass(TestContext testContext) throws Exception {
//Your before goes here.
}
Self-contained in one file that would look like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"commonContext.xml" })
#TestExecutionListeners({SimpleTest.class})
public class SimpleTest extends AbstractTestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) {
System.out.println("In beforeTestClass.");
}
#Test
public void test() {
System.out.println("In test.");
}
}
I came up with the solution of creating a separate initialization method (not setUp) annotated with #PostConstruct. This is not really an elegant solution, but it makes sure that the autowired/injected fields are properly initialized by Spring before using them, (which was the initial problem with the statically #BeforeClass annotated method).
Related
I am writing some JUnit tests with JUnit 5. Before each test I need to load a test resource and initialize some other stuff with it. For that I wrote my init method annotated with #BeforeEach, because that progress is always the same except that the resource to load should be a different one for each test.
I first thought of removing the #BeforeEach annotation, add a parameter to the init method to specify which resource should be loaded and call the init method myself from within each test at the beginning.
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
public class MyTest {
private Object testResource;
private void init(String resourcePath) {
// actually load the resource and initialize some fields here
this.testResource = "Loaded resource from: " + resourcePath;
}
#Test
public void test0() {
init("TestResource0");
assertEquals("Loaded resource from: TestResource0", testResource);
}
#Test
public void test1() {
init("TestResource1");
assertEquals("Loaded resource from: TestResource1", testResource);
}
}
That way I feel like I am undermining the whole structure of the JUnit test flow and I fear, that that could cause some issues in the future when extending the tests, by e.g. some fancy meta test programming, where I'm gonna rely on JUnit to provide the correct information about the current state of the test.
So I decided to keep the parameter for the resource to load on the init method and keep the #BeforeEach annotation. That way I needed to include a ParameterResolver. My first thought about the implementation of resolveParameter(ParameterContext, ExtensionContext) was to first find out what test is about to be executed and return the corresponding resource to be loaded for that test.
static class MyParamResolver implements ParameterResolver {
#Override
public Object resolveParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) throws ParameterResolutionException {
String test = extensionContext.getRequiredTestMethod()
.getName();
switch (test) {
case "test0":
return "TestResource0";
case "test1":
return "TestResource1";
}
throw new ParameterResolutionException("Unknown test " + test);
}
#Override
public boolean supportsParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) {
return true;
}
}
I don't like that solution, because I first dont have safety for the names to be correct ensured by the compiler and secondly the resources to be loaded are not obviously connected to the corresponding test at first sight. I then thought it would be nice to provide the resource path somehow to an annotation, that is directly attached to the test method. Something like that:
#Test("test0")
public void test0() {
assertEquals("Loaded resource from: TestResource0", testResource);
}
#Test("test1")
public void test1() {
assertEquals("Loaded resource from: TestResource1", testResource);
}
...
#Override
public Object resolveParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) {
return extensionContext.getRequiredTestMethod()
.getAnnotation(Test.class)
.value();
}
Unfortunately the #Test annotation doesn't define any parameters and after some research in the JUnit docs I couldn't find any other annotation fitting in here. The best thing I can think of now is to create my own annotation and putting it on each test method. But I also think that this is a common problem, which can be solved without reinventing the weel myself. I just couldn't find anything.
Is there a convenient way to solve this problem, that doesn't need to invent own annotations. In other words: Is there an easy way, that keeps up the code quality and readability to solve this problem by just using the framework API that is already there?
ParameterizedTest is useful when you have the same steps for a test, but want to execute it with different parameters. That doesn't seem to be the case. You can simply use the TestInfo parameter to the #BeforeEach method to handle your case.
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
public class JUnitTest {
#Test public void test1() {
System.out.println("Test");
}
#BeforeEach public void f(TestInfo info) {
System.out.println(info.getDisplayName());
}
}
I guess, you're looking for "container templates". They are not part of Jupiter, yet. But already scheduled for 5.4: https://github.com/junit-team/junit5/issues/871
I have a test class containing test cases for say blue and non-blue devices. If the parameter isBlue is set then it should run only those test case that have say the #Blue annotation. I am not sure how to implement this specific annotation that will achieve this functionality.
public class TestClass {
boolean isBlue = false;
#Before
public void setUp () {
isBlue = MyApplication.instance().isBlue();
}
#Test
public void testA () { ... }
#Test #Blue
public void testB() { ... }
}
In this example if isBlue is true then it should only run testB() otherwise it should run all test cases
Take a look at JUnit runners. Nice explanation of runners
You can create your own runner which will extend on BlockJUnit4ClassRunner.
You can override
#Override
protected List<FrameworkMethod> getChildren() {
// scan test class for methonds annotated with #Test
}
To additionally filter by methods that have your custom annotation set, and your property in the application is set as well.
I think you are on the wrong path.
You want your test cases to help identifying problems; and assist you in fixing them. Anything that "distracts" you from that purpose reduces the values of your unit tests.
Thus: don't put tests that have really "different" scope into the same test class. Especially from the point of view: how would you control what "MyApplication.instance()" would return? That sounds like a problem in itself.
Meaning: you want to have two independent tests; and those don't rely on some "static" object telling them something. They test what is in their scope; nothing else.
By using jUnit Assume
#Test
public void testA () {
assumeTrue(MyApplication.instance().isBlue());
...
}
A failing assumption in a #Before or #BeforeClass method will have the same effect as a failing assumption in each #Test method of the class.
Is it possible to run a JUnit #Test method in a class that has a method annotated with #Before, but to ignore the #Before method only for this test?
Edit: I am interested if JUnit supports this functionality, not workarounds. I am aware of workarounds like moving the test(s) in another class or removing the annotation and manually calling setUp() in each test method.
Suppose in a class there are 30 tests, and for 29 of them #Before really simplifies the testing initialization, but for one (or more than one) of them is useless/it complicates things.
public class MyTestClass {
#Before
public void setUp() {
//setup logic
}
#Test
public void test1() {
//[...]
}
#Test
public void test2() {
//[...]
}
//more tests here
#Test(ignoreBefore = true, ignoreAfter = true //false by default)
//something equivalent to this
public void test20() {
//[...]
}
}
You can do this with a TestRule. See my answer to Exclude individual test from 'before' method in JUnit. Basically, implement ExternalResource, and in the apply method, check if there is a specific annotation on the method, and if there is, don't run the before/after method. You'll have to specifically call the before/after from your rule though.
If it useless it should not be a problem - does it harm to run the setUp once more?
However I don't think it's possible and looks for me as a cripple feature.
Another approach - move that test to a separate test-class.
With JUnit 5 You can have nested tests using #Nested annotation :
public class MainClass {
#Nested
class InnerClass1 {
#BeforeEach
void setup(){}
#Test
void test1(){}
}
#Nested
class InnerClass2 {
// No setup
#Test
void test2(){}
}
}
Just to add to this, something that I found out on a recent visit to this area.
Junit/Mockito seems to give preference to mocking behavior defined in a test, over a #Before annotated method.
We have DAO tests that should run against both the real DAO/database, and against a mock dao to verify that the mock dao behaves the same as the real dao. To this end, we have a structure like this:
public abstract class DAOTestBase
{
public void testSimple()
{
// dummy assertion
assertTrue(true, "Hello");
}
}
#Test(groups = "fast")
public class TestMockDAO extends DAOTestBase
{
// setUp/tearDown and helper methods for mock
}
#Test(groups = "slow")
public class TestDAO extends DAOTestBase
{
// setUp/tearDown and helper methods for real DB
}
Unfortunately this doesn't work - TestNG doesn't think that the testSimple method is a test and hence won't run it. So instead I tried to annotate the testSimple method (or the DAOTestBase class):
A #Test annotation without any groups will lead to the same effect - the test won't run for either fast nor slow groups.
A #Test annotation with groups fast and slow will lead to the opposite effect - both TestMockDAO and TestDAO will be run regardless of whether only fast or only slow tests should be run.
A #Test annotation with a different group, say common, plus added dependsOnGroups="common" annotations in both TestMockDAO and TestDAO will also not work unless common is included in the groups to run which leads again to case 2 above (both TestMockDAO and TestDAO are run).
In the end, what I'm looking for is a way to be able to define the group for the inherited tests in the sub class, but it seems as if the #Test annotation is only applied to test methods in that very same class, not also to inherited methods that don't have a #Test annotation. Is there any other way to achieve this (without overriding all methods in the sub classes) ?
I am currently working through a similar situation.
A way to make test cases run is to use something like:
#Test
public void someTest() {
TestNG testng = new TestNG();
testng.setTestClasses(new Class[] { SomeTests.class });
testng.run();
}
Reference: http://testng.org/doc/documentation-main.html#running-testng-programmatically
Unforunately I am currently unable to get it to report the test cases within SomeTests.
Have you tried simply adding a #Test annotation on top of DAOTestBase? Each subclass will override it with its own group and this should make the method in the base a test method.
I am using TestNG 6.14.3 version and I found a solution using priority annotation.
Example:
I have a base test class:
public class TestBase {
#Test(priority = 0)
public void testA() {
assertTrue(true, "testA");
}
}
And another extended test class:
public class Test2 extends TestBase {
#Test(priority = 1)
public void testB() {
assertTrue(true, "testB");
}
}
When I run Test2 test class, I obtain the following esult:
testA: true
testB: true
I solved it this way:
The methods in the base class are in "base" group, but need to check if the test have been initialized.
public abstract DaoTestBase {
private boolean initialized = false;
#Test(groups = "base")
public void testSimple() {
if (!initialized) { return; }
// dummy assertion
assertTrue(true, "Hello");
}
}
The test is initialized in the child, in the BeforeClass annotated method.
#BeforeClass
protected void initialize() {
super.initialized = true;
}
If you annotate the parent class instead of the methods, you must pass inheritGroups=false and the group, since it inherits also the group of the base class and it will not work.
Now, you must run TestNG to check groups base,fast or base,slow. Both tests will be executed, but the one not initialized will do nothing.
It is ugly, and I would not recommend it (it looks better to redefine the methods in child and call the according super method), but in my case I need priority in my test methods, and I want to avoid that repetition in each child class.
I have some common set up code that I've factored out to a method marked with #Before. However, it is not necessary for all this code to run for every single test. Is there a way to mark it so the #Before method only runs before certain tests?
Just move out the tests that don't need the setup code into a separate test class. If you have some other code common to the tests that would be helpful to keep, move that out into a helper class.
#Nested + #BeforeEach
Totally agree with the point of moving the related code to an inner class. So here what I have done.
Create an inner class inside your test class
Annotate the inner class with #Nested
Move all the test methods you want to use in the inner class
Write the init code inside the inner class and annotate it with #BeforeEach
Here is the code:
class Testing {
#Test
public void testextmethod1() {
System.out.println("test ext method 1");
}
#Nested
class TestNest{
#BeforeEach
public void init() {
System.out.println("Init");
}
#Test
public void testmethod1() {
System.out.println("This is method 1");
}
#Test
public void testmethod2() {
System.out.println("This is method 2");
}
#Test
public void testmethod3() {
System.out.println("This is method 3");
}
}
#Test
public void testextmethod2() {
System.out.println("test ext method 2");
}
}
Here is the output
test ext method 1
test ext method 2
Init
This is method 1
Init
This is method 2
Init
This is method 3
Note: I am not sure if this is supported in Junit4. I am doing this in JUnit5
It is possible to achieve also via Assume from JUnit. And then you can check the method name for which you want to process #Before.
public class MyTest {
#Rule
public TestName testName = new TestName();
#Before
public void setUp() {
assumeTrue(testName.getMethodName().equals("myMethodName"));
// setup follows
}
}
Check the topic for more insights about #Rule.
Now that it's 2023, I'd recommend sticking with JUnit 5.x
I'd also say that this is probably a micro-optimization. I would not go to the effort until I measured my test time and saw that running the code when it wasn't necessary added a significant amount of time.
Not sure about #Before, but I recently came up with a strategy for #After block to run selectively. The implementation was straight forward. I have some flags set to default values as part of the test class. They are reset to default values in #Before class. In the class I need to do things specific to a flag, I set those flags & in #After I check for flag values to do the respective jobs.
JUnit 4.12 provide Enclosed Runner like
#RunWith(Enclosed.class)
public class GlobalTest{
#RunWith(MockitoJUnitRunner.class)
public class InnerTest{
}
}