Set JUnit timeout in eclipse

Multi tool use
Multi tool use

The name of the picture


Set JUnit timeout in eclipse



Question



When I run all our JUnit tests, using eclipse, can I set a default timeout?



Background



My manager insists on writing Unit tests that sometimes take up to 5 minutes to complete. When I try to run our entire test suite (only about 300 tests) it can take over 30 minutes. I want to put something in place that will stop any test that takes longer than 10 seconds.



I know an individual test can be annotated with:


@Test(timeout=10000)



But doing this would make his long tests always fail. I want them to work when he runs them on his box (if I have to make minor adjustments to the project before checking it in, that's acceptable. However, deleting the timeouts from 40 different test files is not practical).



I also know I can create an ant task to set a default timeout for all tests, along the lines of:


<junit timeout="10000">
...
</junit>



The problem with that we typically run our tests from inside eclipse with Right Click > Run As > JUnit Test.



Summary



So is there a relatively painless way to set a timeout for all tests, perhaps using a Run Configuration setting, or project setting, or JUnit preference, or environment variable, or something? I'd even settle for installing some other plugin that lets me right click on particular test folders and run all the tests in some other manner like through ant or something...





Tests that take 5 minutes? Sounds like they're either doing far too much per test or they're integration tests and not unit tests…
– Donal Fellows
Nov 4 '10 at 14:50







You may separate the integration-test from junit-tests. The long-Running tests should run at a buildserver like hudson, not on your local maschine.
– Christian Kuetbach
Nov 4 '10 at 15:19





@Donal: unfortunately, they are unit tests. I don't like them. I don't agree with them. Yet, I can't do anything about them. Hence my question... My aim is to, at least, neutralize the problem on my box. I think I'm going to write an aspect to annotate all test methods with @test(timeout=10). Then, I will just never check that aspect into Subversion. That's my plan, I think...
– gMale
Nov 5 '10 at 12:29


@test(timeout=10)





the aspect approach didn't work because those methods already have an @Test annotation and there currently is no mechanism in AspectJ for replacing annotations... I think it's in the works, though.
– gMale
Apr 21 '11 at 1:00





@Test(timeout=10) indicates a timeout of 10 ms not 10 s.
– Stephan
Nov 12 '15 at 10:39




@Test(timeout=10)




7 Answers
7



Possible solution:
Extend all your Test classes from another class: TestBase for example


TestBase



Add to TestBase global timeout. This timeout will be applied to all extended classes:


TestBase


public class TestBase {
@Rule
public Timeout globalTimeout = new Timeout(10000);
}





This is a great suggestion. Something that could could definitely be used in other situations. But in this case, it would require changing all his tests, which wasn't an option.
– gMale
Nov 28 '12 at 18:03





Nice trick, but is there any way to override that value for a specific test (e.g only one) extending that class?
– рüффп
Jan 27 '16 at 11:45





Sure. You can use @Test(timeout=10) on specific method in test class
– alaster
Feb 1 '16 at 14:56


@Test(timeout=10)



So maybe a combination of using Infinitest with the "Slow test warning" enabled together with the filtering feature would do the trick. You could identify tests that exceed your time-limit and add them to the filter list, this would only affect testing from inside Eclipse. Running the tests via a possible build script via CLI/CI etc would not be affected at all.
You can find more on setting this up here: http://improvingworks.com/products/infinitest/infinitest-user-guide/





This looks fantastic! Pretty much exactly what I was looking for and something I could use often, in other situations. I'll try this out and if it works, I'm sold...
– gMale
Nov 28 '12 at 18:04



If you want to configure the tests to run for a maximum of ten seconds you can try this:



@Test(timeout=10000)


@Test(timeout=10000)





Thanks but this solution won't work for the situation described in the original question: doing this would make his long tests always fail. I want them to work when he runs them on his box . . . deleting the timeouts from 40 different test files [before checkin] is not practical
– gMale
Nov 28 '12 at 18:00




doing this would make his long tests always fail. I want them to work when he runs them on his box . . . deleting the timeouts from 40 different test files [before checkin] is not practical



My manager insists on writing Unit tests that sometimes take up to 5 minutes to complete



This almost certainly indicates that those tests are not in fact unit tests. Cut that Gordian knot: try refactoring your testsuite to provide equivalent test coverage without requiring a test-case that runs for that long.





Sadly, they are unit tests. He verifies that a low-level function times out after 5 minutes of failing. :( That function has like 3 lines of code.
– gMale
Mar 15 '11 at 6:00





Using a time-out requires a clock. The real code will use the system clock, but your unit tests need not. Abstract the clock to be an object and use dependency injection to remove the direct dependency on the system clock. That is, instead of directly calling the system clock function, introduce a Clock interface (or abstract base class) passed to the time-out code. For the unit tests use a MockClock (that IS-A Clock) that simulates a time-out. For the real, integrated, code use a SystemClock (that IS-A Clock) that calls the system clock function.
– Raedwald
Mar 21 '11 at 9:08


Clock


MockClock


Clock


SystemClock


Clock





Although he's not using a clock, I see your point. In this case, the timeout is actually based on a failed library call (that ultimately times out during I/O). It would be nice if he mocked that call but he doesn't. I can't really change all his tests everywhere, using mocks where I see fit. So I was looking for a way to just set a timeout for all tests. These days, we're back to using ant so I could just use the timeout built into the junit task, as I mentioned in the original post. Ant is great.
– gMale
Apr 21 '11 at 0:58



Almost certainly your bosses tests are system tests pretending to be unit tests. If they are suppsoed to be unit tests and are just slow they should be refactored to use mocks so that they run quicker.



Anyway, a more pragmatic and diplomatic approach than confronting your boss over this might be to just try and run the faster ones yourself. I've seen a hack to do this in a project where slow tests had SytemTest in their names. Then there were two ant targets created in the build file. One that ran all tests and one that filtered out by class name the SytemTests . To implement this all you would have to do is rename some of the tests and write your ant target.


SytemTest


SytemTest



It sounds like test suites would help you out.



You can have two test suites; QuickTests and AllTests. Include QuickTests in the AllTests suite, as well as the tests that take a long time. Then all other tests would go into the quick tests suite.


QuickTests


AllTests



From eclipse you can run an entire test suite at once. So you would run QuickTests and that way all the other slow tests will not run.



Or see this question on how to apply a timeout to a suite which will apply to nested suites and classes in the suite. Which can achieve similar to what you want when combined with my above suggestion.



I know this doesnt really answer your question but the simple answer is don't!



Setting timeouts conditionally is wrong beacsue then you would have Unit tests on your machine that you are always going to fail. The point of Unit tests is to be able to quickly see that you havnt broken anything. Having to check through the failed test list to make sure it's just the long running tests is ust going to make some bugs pass through the cracks.



As some of the commenters mentioned you should split out the tests into unit tests that run quickly and the slower runnning integration tests i.e. have a source folder called src/main/java for your code, src/test/java for unit tests and src/integration-test/java for the longer running tests.





thanks for taking the time to answer but you are preaching to the choir ;) I agree with you 100% but I cannot make such changes. So my question is more about neutralizing the effect of crappy unit tests.
– gMale
Nov 5 '10 at 12:32





@gmale: We've all been there mate but if you don't keep on at your boss nothing will change. Had a quick look at the Ant source code and the timeout they apply isn't a JUnit thing. You might want to use @Ignore for the specific tests you don't want to run instead of an arbitrary timeout. One thing you could do is edit the JUnit source code to set a default timeout. You'd have to change which JUnit library you use.
– brain
Nov 6 '10 at 13:24







This would be more appropriate as a comment.
– byxor
Aug 30 '16 at 9:22






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

o Tp 2dqVc0,KftMm35GowiTy22KHlO,w1psTV G5TnzSWAyGh7qVHzcLj UT,djEramF,vzmu
ckMc,UdF u17naPPL2,I3jtlhdVGeeRN4n AugSAc,XKY2jlV Ig9wW8w89OZVyiYIa,ViW7jBU0XlZgfSy,XZJddLd

Popular posts from this blog

Makefile test if variable is not empty

Will Oldham

Visual Studio Code: How to configure includePath for better IntelliSense results