In a unit test, I need to perform a quite complex setup (this may be a code smell but this is not what this question is about :-)). What I'm interested in is if it is better to have multiple #Before methods performing the setup or just one, which calls helper methods to perform the initialization.
E.g.
#Before
public void setUpClientStub() {
}
#Before
public void setUpObjectUnderTest() {
}
vs.
#Before
public void setUp() {
setUpClientStub();
setUpObjectUnderTest();
}
As has been said in other responses, the order in which JUnit finds methods is not guaranteed, so the execution order of #Before methods can't be guaranteed. The same is true of #Rule, it suffers from the same lack of guarantee. If this will always be the same code, then there isn't any point in splitting into two methods.
If you do have two methods, and more importantly, if you wish to use them from multiple places, then you can combine rules using a RuleChain, which was introduced in 4.10. This allows the specific ordering of rules, such as:
public static class UseRuleChain {
#Rule
public TestRule chain= RuleChain
.outerRule(new LoggingRule("outer rule"))
.around(new LoggingRule("middle rule"))
.around(new LoggingRule("inner rule"));
#Test
public void example() {
assertTrue(true);
}
}
This produces:
starting outer rule
starting middle rule
starting inner rule
finished inner rule
finished middle rule
finished outer rule
So you can either upgrade to 4.10 or just steal the class.
In your case, you could define two rules, one for client setup and one for object, and combine them in a RuleChain. Using ExternalResource.
public static class UsesExternalResource {
private TestRule clientRule = new ExternalResource() {
#Override
protected void before() throws Throwable {
setupClientCode();
};
#Override
protected void after() {
tearDownClientCode()
};
};
#Rule public TestRule chain = RuleChain
.outerRule(clientRule)
.around(objectRule);
}
So you'll have the following execution order:
clientRule.before()
objectRule.before()
the test
objectRule.after()
clientRule.after()
I would do the latter. AFAIK, there is no way to guarantee order of #Before annotated setup methods.
Note that there are no guarantees about the order in which #Before annotated methods are invoked. If there are some dependencies between them (e.g. one method must be called before the other), you must use the latter form.
Otherwise this is a matter of preference, just keep them in a single place so it is easy to spot them.
I don't think it makes much of a difference, but I personally prefer the second one (the order Before methods are executed being not defined, you'll have a better control that way).
For me it seems using JUnit 4.12, the methods annotated with #Before get indeed sorted deterministically by the following characteristic:
by reversed lexicographic order with respect to the method name.
You can see this behaviour by executing this Testclass:
import java.util.Arrays;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
/*
* key points:
* - multiple #Before methods get sorted by reversed lexicographic order
* */
public class JUnitLifecyle {
#BeforeClass
public static void runsOnceBeforeClassIsInited() {
System.out.println("#BeforeClass");
}
public JUnitLifecyle() {
System.out.println("Constructor");
}
#Before
public void a() {
System.out.println("#Before a");
}
#Before
public void b() {
System.out.println("#Before b");
}
#Before
public void cd() {
System.out.println("#Before cd");
}
#Before
public void ca() {
System.out.println("#Before ca");
}
#Before
public void cc() {
System.out.println("#Before cc");
}
#Before
public void d() {
System.out.println("#Before d");
}
#Before
public void e() {
System.out.println("#Before e");
}
#Test
public void firstTest() {
System.out.println("#Test 1");
}
#Test
public void secondTest() {
System.out.println("#Test 2");
}
#After
public void runsAfterEveryTestMethod() {
System.out.println("#After");
}
#AfterClass
public static void runsOnceAfterClass() {
System.out.println("#AfterClass");
}
}
I came to this conclusion after playing around with the output, while changing the method names of the methods annotated with #Before.
Keeping this reversed lexicographic order in mind you could name your methods accordingly to let JUnit execute your setup tasks in the right order.
Although the above approach is possible, I think you should not do this in your tests, because the Java-Annotations thing in JUnit was introduced to get away from convention-based testing.
I declared all my #Before methods private and created a single method annotated with #Before that called all those and my tests worked. I have worked in kotlin.
Here's how you can do it:
private fun setUpClientStub() {
//whatever you want to do
}
private fun setUpObjectUnderTest() {
//whatever you want to do
}
#Before
fun setUp() {
setUpClientStub()
setUpObjectUnderTest()
}
#Test
fun test() {
//your test logic
}
This way you can ensure that your methods are called in the right order and you can name them any way you want.
Related
I have a JUnit test class which runs 15 tests. 5 of the tests are optional in that I only wish to run them if a particular variable gets initialized by an argument. If the variable value is null I'd like to ignore these tests. Is this possible and if so, how?
You could use JUnit4's Assume feature ...
It's good to be able to run a test against the code as it is currently written, implicit assumptions and all, or to write a test that exposes a known bug. For these situations, JUnit now includes the ability to express "assumptions"
For example:
#Before
public void setUp() {
org.junit.Assume.assumeTrue(yourCondition());
// ...
}
If yourCondition() does not return true then the test for which #Before is running will not be executed.
Approach 1:
You can use JUnit-ext. It has RunIf annotation that performs conditional tests, like:
#Test
#RunIf(DatabaseIsConnected.class)
public void calculateTotalSalary() {
//your code there
}
class DatabaseIsConnected implements Checker {
public boolean satisify() {
return Database.connect() != null;
}
}
Approach 2
Another approach is to use Assume. You can do it in a #Before method or in the test itself, but not in an #After method. If you do it in the test itself, your #Before method will get run. You can also do it within #BeforeClass to prevent class initialization. For example:
#Before
public void beforeMethod() {
org.junit.Assume.assumeTrue(someCondition());
}
Approach 3
I think an another option for you may be to create an annotation to denote that the test needs to meet your custom criteria, then extend the default runner with your own and using reflection, base your decision on the custom criteria. It may look something like this:
public class CustomRunner extends BlockJUnit4ClassRunner {
public CTRunner(Class<?> klass) throws initializationError {
super(klass);
}
#Override
protected boolean isIgnored(FrameworkMethod child) {
if(shouldIgnore()) {
return true;
}
return super.isIgnored(child);
}
private boolean shouldIgnore(class) {
/* some custom criteria */
}
}
Suppose I have one test class with three test methods. The tests may either run serially or in two separate threads. Each test method requires its own instance of a collaborator (such as a resource of some kind). However, this would not seem to cut it:
public class MyTestClass {
private Resource resource;
#BeforeMethod public void setupResource() {}
#AfterMethod public void tearDownResource() {}
#Test public void testMethod1() {}
#Test public void testMethod2() {}
#Test public void testMethod3() {}
}
This seems to work when run serially, but if we run the three test methods in parallel (with method granularity), it would seem that because all three tests are invoked via the same instance, the resource variable ends up being overwritten repeatedly.
So, how about this:
public class MyTestClass {
private static ThreadLocal<Resource> resource;
#BeforeMethod public void setupResource() {}
#AfterMethod public void tearDownResource() {}
#Test public void testMethod1() {}
#Test public void testMethod2() {}
#Test public void testMethod3() {}
}
This seems plausible, and it looks like it can old up if I throw in #DataProvider and test listeners as well (provided setupResource() and tearDownResource() is properly implemented, so that if there are two threads to run tests on, the third method doesn't have any "leftovers" from the first).
Having said that, it seems quite cumbersome to have a #BeforeMethod, an #AfterMethod, and wrapping the collaborator (Resource) in a ThreadLocal. Is there any other good "test-local" alternatives worthy of consideration?
I think you can set up a threadlocal container separately. Something like below; create a Mythreadlocal container class.
public class ThreadLocalContextObject{
private Resource resource;
// getter and setter for above
}
public class MyThreadLocal {
public static final ThreadLocal threadLocal = new ThreadLocal();
public static void set(ThreadLocalContextObject ctx) {
threadLocal.set(ctx);
}
public static void unset() {
threadLocal.remove();
}
public static ThreadLocalContextObject get() {
return threadLocal.get();
}
}
Then from #BeforeMethod you can set the context object holding the resource in the MyThreadLocal. And from the #AfterMethod you can unset it from the threadlocal storage by calling unset.
Note unsetting the threadlocal is necessary failing which can easily cause you run out of memory.
The threadlocal will gurantee the local storage of the resource for the thread executing a particular test case.
So answering your question the threadlocal might be the easiest and safest way to do this stuff according to me.
how can I reuse JUnit tests in another testclass?
For example:
public TestClass1 {
#Test
public void testSomething(){...}
}
public TestClass2 {
#Test
public void testSomethingAndSomethingElse() {
// Somehow execute testSomething()
// and then test something else
}
}
Avoid the scenario, in general. It is prone to making tests much more brittle. If TestClass1 fails, then TestClass2 implicitly fails, which isn't desirable for at least the following reasons:
Code is tested more than once, which wastes execution time.
Tests should not rely on each other, they should be as decoupled as possible
If this becomes a pattern, it will become harder to identify what section of code is broken by looking at which tests are failing, which is part of the point of tests
Occasionally sharing sections of test code is useful, particularly for integration tests. Here's how you might do it without depending on the tests themselves:
public abstract BaseTests {
protected void somethingHelper() {
// Test something
}
}
public TestClass1 extends BaseTests {
#Test
public void testSomething(){
somethingHelper();
}
}
public TestClass2 extends BaseTests {
#Test
public void testSomethingAndSomethingElse() {
somethingHelper();
// and then test something else
}
}
Alternatively, you could use a helper class and avoid the inheritance altogether. Asserts and the like can go in the somethingHelper() method.
Don't call a method from TestClass1 in TestClass2 directly. The test cases become less readable this way, and can lead to spaghetti frittata.
As usual you can:
Extends TestClass2 from TestClass1
Access TestClass1 from TestClass2 using delegation:
Example 1:
// Instantiate TestClass1 inside test method
public TestClass2 {
public void testSomethingAndSomethingElse1() {
new TestClass1().testSomething();
}
}
Example 2:
// Instantiate TestClass1 as a member of TestClass2
public TestClass2 {
private TestClass1 one = new TestClass1();
public void testSomethingAndSomethingElse1() {
one.testSomething();
}
}
This is common to run a test with a different configuration. Do not worry about and go ahead.
At the first step create your own test without considering any configuration:
public abstract BaseTests {
#Test
protected void somethingHelper() {
// Test something
}
}
Then, extend the test class and add some configuration:
public TestClass1 extends BaseTests {
#Before
public void setup(){
// TODO: config
}
}
It is not necessary to do specific configuration but it is very common with a configurable system (the main functionality of the system must be valid for each config).
In the other test case:
public TestClass2 extends BaseTests {
#Before
public void setup(){
// TODO: other config
}
}
For example, there may be an encryption and decryption process where the sequence of encryption>decryption must be identified. On the other hand, there is a different algorithm to use while the test process is unique.
Logically, there is no reason to call one test method from another. Any tool that runs one test would just as easily all tests in the package. But if you need to, you'd call it like any other method in any other class.
What you most likely want to do, is perform some common setup for both test methods. You could put that code in a utility method in a common class, and invoke the common code in both tests.
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.
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{
}
}