I have a JUnit test class with a number of different test cases. One of these test cases has bit different test setup and cleanup than the other ones. What is the best way to do test cleanup in such scenario? Extract test case into separate class and use standard #Before and #After annotations?
Make a subclass with only that test, write custom #Before and #After methods calling super ones if needed.
Related
In order to use JUnit's TestCase methods such as setUp() and tearDown(), I have to have my test class extend TestCase.
In order to user JUnit's TestResult methods such as addFailure() and addError(), I have to have my test class extend TestResult.
Java does not allow for multiple inheritances, so how do I gain access to both of these (or more) classes in my tests?
OR: am I misunderstanding the purpose of the TestResult class, and this isn't something I should be doing?
Because I would imagine that I should be able to test an assertion (or other test) inside a try block for example, then catch and subsequently addError the caught exception.
I understand that,
#Before and #BeforeClass run before each test, or the entire test class, respectively
#Rule and #ClassRule wraps each test, or the entire test class, respectively.
Let's say I need to initialize some data before each test method,
How do I decide between using #Before and #Rule? Under what conditions is one preferred over another? The same question also goes for #BeforeClass vs.#ClassRule.
In order to use #Rule, you require a class that implements TestRule(preferred) or MethodRule, as can be read here.
Whereas #Before and #After require a new method to be written in every test case, #Rule does not because it is only an instantiation of already existing code.
So, if you would use #Before and #After for setUp() and tearDown() that you'll be using in many test cases, it is actually a better idea to use #Rule because of code reuse. If you have a test case that requires a unique #Before and/or #After, then these annotations are preferable.
For a bit more elaborate answer with a couple examples, take a look here. Ajit explains it very well.
Indeed, as #Quwin suggested, accoridng to JUnit 4.12 API doc,
TestRule can do everything that could be done previously with
methods annotated with #Before, #After, #BeforeClass, or
#AfterClass, but TestRules are (1) more powerful, and (2) more easily shared
between projects and classes.
Ways that TestRules are more powerful:
There are known implementing classes of the TestRule, which are some usefuls rules you can use out-of-the-box,
For examples of how this can be useful, see these provided TestRules, or write your own:
ErrorCollector: collect multiple errors in one test method
ExpectedException: make flexible assertions about thrown exceptions
ExternalResource: start and stop a server, for example
TemporaryFolder: create fresh files, and delete after test
TestName: remember the test name for use during the method
TestWatcher: add logic at events during method execution
Timeout: cause test to fail after a set time
Verifier: fail test if object state ends up incorrect
Another benefit of rules, is that multiple rules can be used in a single test case. You may want to use RuleChain to specify the order in which the rules should be run.
I have created several tests cases for my application, all these are chained in a single test suite class.
However, i would like to pass an object created in the first test to the others.
To be clearer, the first test tests a class that creates a complex object with data coming from my database. I would like the others to test the methods of the object itself.
Here is how i define my test suite class:
package tests.testSuites;
import tests.Test1;
import tests.Test2;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(Suite.class)
#SuiteClasses({
Test1.class
Test2.class
})
public class DataTestSuite {
}
But I would like to have something like this somewhere:
MyObject obj=Test1.testcreation();
Test2.testMethod(obj);
How can I combine a regular JUnit testSuite class definition with the need to pass the created object to my other test?
EDIT
For information, the test suite is launched in a test runner class. This class helps formatting the results and creates a custom log file.
This is how it calls the test suite:
public class MetExploreTestRunner {
public static void main(String[] args) {
Result result=JUnitCore.runClasses(DataTestSuite.class);
if(result.wasSuccessful()){
System.out.println("All tests succesful ");
}else{
for(Failure failure:result.getFailures()){
System.out.println(failure.toString());
}
}
}
}
Do not do that. Each test should be independent of the others. You can then run tests singly, to debug them, and each test is easier to understand. Also, JUnit runs tests in an arbitrary order; you can not guarantee that the object will be created before it is used.
If several tests use a similar object, consider extracting the code for creating it into a shared private method of the test class. If many tests use the object, consider making it a test fixture set up by a #before method.
After a lot of searching on the internet, I found what I was looking for.
The library JExample allows you to create dependencies between different tests and to pass arguments between them which is what I needed. http://scg.unibe.ch/research/jexample
I really recommend it.
Thank you all for your answers
You can use #Rule instead of reuse some data from one test to the others. You can see an example of use here: https://github.com/junit-team/junit/wiki/Rules
That rule can create that big object and then you can use it in every test you want.
I don't recommend you to create any dependency between tests because things could change in the future and you'd have to change many things in your other tests.
If you really want to do what you said, there is an annotation #dependsOn that would be usefull for you
It seems that you are doing integration testing instead of unit tests.
What you can do is to:
Create mock class that connects to your database and creates this complex object
Write a new class that will run all your tests and will create an instance of your mock class (this might be helpfull http://www.tutorialspoint.com/junit/junit_suite_test.htm )
Create methods with #BeforeClass annotation that will get this object.
Run your tests.
For my point of view it is not very practical, and not unit test at all. Unit tests should be independent, and do not rely on other tests.
Why not factor out the creation of MyObject to a utility class?
public class Test2{
...
#Test
public void testMethod(){
MyObject obj = TestUtil.createMyObject();
//do test here
}
}
You can then call the TestUtil.createMyObject() from any test. Also if creating MyObject is expensive, you can lazily create it and cache the result or use any of the other patterns useful for factory methods.
I very much understand what #BeforeClass is. It is executed once before JUnit test run is started & #Before method is executed before every test case.
My question is regarding a very old post by a very senior stackoverflow user (Péter Török
68.8k) Please refer [stackoverflow question]
[1]: JUnit: using constructor instead of #Before which was posted about 2 yrs ago but on JUnit4. so I think it is still valid and true.
Here he mentions
#Before is equivalent to constructor of test class
and
JUnit creates a new instance of the test class for each #Test,
So how does JUnit manage running #BeforeClass only once which is defined inside the test class?
Methods annotated with #BeforeClass must be static. JUnit doesn't need any instance of the test class to call it.
Well, jUnit could run the method annotated with #BeforeClass at time of class loading, that is like you would implement on your own with a static initializer.
You get also the hint that jUnit is doing something like this by the fact that #BeforeClass and #AfterClass annotated methods must be static.
That's because #BeforeClass has to be a static method. Once it is static, JUnit knows how to run it once.
Sometimes several tests need to share computationally expensive setup (like logging into a database). While this can compromise the independence of tests, sometimes it is a necessary optimization. Annotating a public static void no-arg method with #BeforeClass causes it to be run once before any of the test methods in the class. The #BeforeClass methods of superclasses will be run before those the current class. Static methods are not belongs to instances of the class. Those are properties of the class.
I have two test classes written using junit
TestClass1
TestClass2
If we need to ensure that TestClass2 is run only after TestClass1 in executed. How do we achieve this?
You can achieve this using the Junit test suite. When you specify the list of classes to be executed in a test suite, you're defining an array, and these test classes will be executed in order, except when you're doing parallel execution.
Note that JUnit does not guarantee the order of execution of tests within a class.