JUnit Common setup with custom rollback rules - java

I have a large integration test suite that takes a long time to run. Most of this is due to setup of data. So I need to reduce the amount of time it takes to setup the data for the tests.
After doing some analysis, I see that there groups of tests that have common setup (using #Before annotation for example).
Is there a way to set up some rollback rules in spring and junit so that the data can be set up within a transaction (so it can be rolled back), then each test runs and rolls back to this point. Therefore the set up is only required once. Then at the end of the group, the setup is rolled back?

JUnit provides various test fixtures to accomplish what you want. In JUnit 4, you can use the following:
#BeforeClass: Executed once before the test class starts.
#AfterClass: Executed once after the test class ends.
#Before: Executed before each test case (#Test).
#After: Executed after each test case (#Test).
Hence, you could use #BeforeClass for an one-time setup and #Before/#After for "rollbacks".

Related

Parallel integration tests handle database counts

I'm running my integration tests in parallel but I have one tests that counts the number of rows in one table but the number can vary depending on many tests have run before that tests runs.
Is there any mechanism in Spring or Junit that would allow me to make sure that when that tests runs that table is clean so that the count would always be 1?
Thanks
You can use BeforeEach annotation within Junit class:
#BeforeEach
void foo() {
clearDBrows();
}
void clearDBrows(){
//clear db rows
..
}
This is by considering, your other test's wont really care if db table rows get cleared before execution as #BeforeEach will get executed for every tests you run.

Junit - Should you create a db connection at beforeclass or before?

When doing integration tests it is often the case that you need to connect to a database and do some changes.
Should this be done in #BeforeClass or #Before in junit?
I use #BeforeClass to set up a database connection. The Javadocs for #BeforeClass indicate that #BeforeClass is better for setting up expensive resources such as database connections.
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.
If you use #Before, then a new Connection will be created for every #Test method, which sounds undesirable for just about all use cases.
Use #BeforeClass to set up your database connection. Also use #AfterClass to close your connection.
The code marked #Before is executed before each test, while #BeforeClass runs once before the entire test fixture. If your test class has ten tests, #Before code will be executed ten times, but #BeforeClass will be executed only once.
So to answer your question, you should be using #BeforeClass assuming all your test cases shares same db connection.
If you intend the test methods to all use the same Connection then you should obtain it in a #BeforeClass method. If you want each test method to use its own Connection then you should obtain it in a #Before method. The latter better isolates your tests from each other, but there could be cases where the former is more appropriate.

What happens after a JUnit method has been executed?

I have a JUnit class which deals with testing the clock in my system. The clock has a method jump(long milliSeconds which basically makes the clock jump to the specified time and thus sets the instance field of clock's currentTime to the parameter passed to the jump method.
So I have three JUnit methods. In the first I'm simply testing that the current time of the clock is 0, because I haven't invoked anything on the clock. Then I'm just testing that making the clock jump to a specified time once is reflected on the current time correctly. Lastly, I'm invoking the jump method a few time and after each jump I'm testing whether the current time is correct.
The problem I'm having is that sometimes my JUnit tests pass sometimes they fail. Assume I run the above three JUnit methods once, and it passes. That's fine. Then if I run the three again, then the first one fails because the current time of the clock is NOT 0 anymore but instead the current time is the last jump that was invoked in last test.
I'm confused about this because I thought that after executing all three JUnit methods sequentially it doesn't "remember" what it did if I run the tests again.
So does that require me to initialize the current time to be 0 in the #Before setUp() ? The thing is it's only sometimes that the above occurs. If I wait 5 minutes and run it again. It runs fine. Then if I immediately run it after again, I get the same error.
Has it perhaps something to do with the fact that I have declared the Clock class as final? Or that I have enforced the Singleton design pattern on it?
You designed the Clock as a singleton: there is only one instance of Clock per classloader: Clock.INSTANCE. So obviously, if a method of a test affects the state of the clock, the next method will find this clock with this new state.
You've just rediscovered one of the reasons why singleton is an anti-pattern: it's hard to unit-test. Every test should not assume anything about the clock, and put it in a well-known initial state before testing.
Or you could simply design the Clock as a plain old Java object that you can instantiate in the setup of your test, and use an IOC container to inject a unique instance of Clock in your beans at runtime.
Also, note that unit tests are supposed to be independant from each other. You might want to execute all tests, or only one of them, and they should be able to run in any order.
In JUnit the ordering of test-method invocations is not guaranteed, this is explained in the Junit FAQ section.
Your implementation is using a singleton, so as exposed before the order in which JUnit runs the test is going to affect the test results.
It's not a good practice that tests depends from each others, but if you need to ensure that you could use TestNG.
To fix that use a simple POJO class and let some DI framework handle that. If it's a constraint and you should preserve your class as it, test it with TestNG or rewrite your tests to ensure the order that you need. I.e: I think that a good test could be check that a lower specified time could throws an Exception.

Will JUnit ever run test in parallel?

I was writting JUnit test. I would like to know if the tests within a test class can run in parallel.
class TestMyClass {
#Test
public void test1() {
}
#Test
public void test2() {
}
}
Will Junit ever run test1() and test2() in parallel?
Consider TestNG if you are looking for Parallel tests execution.
Yes, you can. Take a look at this question for details on how to set that up. The correctness of your tests should not really on this behaviour though. Your tests should run correctly if they're run concurrently or not.
I cannot directly answer on whether jUnit will run them in parallel or not, but theoretically that shouldn't matter. The only thing you should keep in mind is the sequence of execution you can bet on, like
setup
execution of test
teardown
This should be enough, as each single test should be completely independent from each other. If your tests depend on the order they're executed or whether they run in parallel, then you probably have some wrong dependencies.
No, because a fixture is setUp before each test. Running test in parallel could change the fixture state. I guess you could write a test executor to run tests in parallel.

Can I skip a JUnit test while the test is running?

Suppose I want to manually run from my IDE (Intellij IDEA, or eclipse) 4000 JUnit tests; the first 1000 tests run pretty smoothly (say they take 3 minutes all 1000) but the test 1001 takes alone over 30 minutes.
Is there a way I can skip the test 1001 (while it's still running) and to let the test 1002 (and the others) keep going. I do not want to #Ignore the test 1001 and rerun the suite because I already have the answer for tests 1-1000; also I do not want to select tests 1001-4000 because it takes too much time.
I would some kind of button - Skip Current Test - which can be pressed when the test is running.
In case such feature does not exist, an enhancement for it needs to be done by the IDE developers or by JUnit developers?
This is actually pretty simple with JUnit 4 using Assume. Assume is a helper class like Assert. The difference is that Assert will make the test fail while Assume will skip it.
The common use case is Assume.assumeTrue( isWindows() ) for tests that only work on, say, a Windows file system.
So what you can do is define a system property skipSlowTests and add
Assume.assumeTrue( Boolean.getBoolean("skipSlowTests") )
at the beginning of slow tests that you usually want to skip. Create an Eclipse launch configuration which defines the property to true and you have a convenient way to switch between the two.
If you want to run a slow test, select the method in Eclipse (or the whole class) and use "Run as JUnit Test" from the context menu. Since the property is false by default, the tests will be run.
No, you cannot skip tests if they are already running.
What I suggest you do is use Categories to separate your slow tests from the rest of your tests.
For example:
public interface SlowTests {
}
public class MyTest {
#Test
public void test1{
}
#Category(SlowTests.class)
#Test
public void test1001{
// this is a slow test
}
}
Create a test suite for the fast tests.
#RunWith(Categories.class)
#ExcludeCategory(SlowTests.class)
#SuiteClasses(MyTest.class)
public class FastTestSuite {
}
Now execute the FastTestSuite if you don't want to run the slow tests (e.g. test1001). Execute MyTest as normal if you want to run all the tests.
What you're asking for is to stop executing your code while it is in mid test. You can't stop executing a current test without having hooks in your code to allow it. Your best solution is to use Categories as others have suggested.
Basically, JUnit executes all of the #Before methods (including #Rules), then your #Test method, then the #After methods (again, including #Rules). Even assuming that JUnit had a mechanism for stopping execution of it's bits of the code (which it doesn't), most of the time is spent in your code. So to 'skip' a test which has already started requires you to modify your test code (and potentially the code that it's testing) in order that you can cleanly stop it. Cleanly stopping an executing thread is a question in itself [*].
So what are your options?
Run the tests in parallel, then you don't have to wait as long for the tests to finish. This may work, but parallelizing the tests may well be a lot of work.
Stop execution of the tests, and fix the one that's you're working on. Most IDEs have an option to kill the JVM in which the tests are running. This is definitely the easiest option.
Implement your own test runner, which runs the test in a separate thread. This test runner then either waits for the thread to finish executing, or checks a flag somewhere which would be a signal for it to stop. This sounds complicated, because you need t manage your threads but also to set the flag in a running jvm. Maybe creating a file somewhere? This runner would then fail the currently running test, and you could move on to the next. Please note that 'stopping' a test midway may leave stuff in an inconsistent state, or you may end up executing stuff in parallel.
There are parallel JUnit runners out there, and I don't think you're going to get much help from IDE developers (at least in the short term). Also, look at TestNG, which allows stuff to be run in parallel.
For using categories, one solution I use is to run the long running tests separately using maven surefire or similar, not through the IDE. This involves checking out the source code somewhere else on my machine and building there.
[*]: Java, how to stop threads, Regarding stopping of a thread
I think a more common solution is to have two test suites: one for the fast tests and another for the slow ones. This is typically the way you divide unit tests (fast) and integration tests (slow).
It's highly unlikely that you'll get modifications to JUnit or IntelliJ for something like this. Better to change the way you use them - it'll get you to an answer faster.
You can modify your thest and do something like
public void theTest(){
if (System.getProperty("skipMyTest") == null){
//execute the test
}
}
and pass the environment variable if you want to skip the test

Categories

Resources