17

I have in my project a lot of unit tests, written in JUnit and TestNG. The building process is based on maven with surefire plugin.

Is there any way/plugin for maven to fail the build when at least one unit test takes too many seconds? I know that there are some plugins to fail build in TeamCity, Jenkins but this is "too far".

In my project I want to have only fast tests to have unit testing process effective. I can improve my old tests but I need to protect for the future commitments

5
  • Failing unit tests because they run too long is part of the framework you're using to run these test cases. Are you using JUnit or TestNG? Commented Feb 16, 2012 at 13:38
  • I don't want to fail separate unit test, I want to fail all build if at least one unit test takes too long. I'm using JUnit and TestNG Commented Feb 16, 2012 at 13:45
  • If you fail one unit test it will fail the build also unless you ask the plugin not too. Commented Feb 16, 2012 at 13:46
  • right, but I can't just add the timeout annotation to all my unit tests. This is too painful and don't resolve problem in the future Commented Feb 16, 2012 at 14:02
  • 1
    You can also just set the timout at the suite level in your testng xml file. <suite name="Integration Suite" time-out="30000"> Commented Feb 16, 2012 at 14:30

6 Answers 6

15
+100

If all your tests extend some base class, I think you can stick @Rule in there which will apply to all the @Test in the child class.

e.g.

import org.junit.rules.Timeout; public abstract class BaseTestConfiguration { @Rule public Timeout testTimeout = new Timeout(60000); // 60k ms = 1 minute } public class ThingTests extends BaseTestConfiguration { @Test public void testThis() { /*will fail if not done in 1 minute*/ } @Test public void testThat() { /*will fail if not done in 1 minute*/ } } 

We found this to be easiest rather than messing with AspectJ or secret configuration directives. Devs are more likely to figure out the Java parts than all the secret XML this and that. You can put @Before @After and any number of other junit directives in the base class too.

Sign up to request clarification or add additional context in comments.

3 Comments

But in his scenario we have many test cases. We need to extend all the tests to BaseTestConfiguration.
While this is an extra step to creating tests, this is by far the easiest implementation I've yet seen.
Yeah I realized that was definitely a critical caveat, that you might have to put in an initial cost to get all your tests to extend something when they didn't already. Since the OP has more information than we do, figured it worth mentioning anyways.
7

In maven surefire, you can use forkedProcessTimeoutInSeconds, along with forkMode=once.

This will kill the forked jvm if it takes too long. If you want to do this per test, you can forkMode=pertest or forkMode=always (which does it for each class).

1 Comment

in real world - forking is not effective
4

Why don't add a timeout on a per test basis. I assume you're programming in Java, so in JUnit you can do something like this:

 @Test(timeout=100) public void testQuickly() 

If the test doesn't end after 100 milliseconds, it will fail.

1 Comment

What if you have gazillions tests and want to have one constant value in seconds to control this requirements? It can't be set per test.
1

Have you tried specifying the timeout for the test through @Test(timeout=xx)? Find the official api documentation here: http://junit.sourceforge.net/javadoc/org/junit/Test.html

EDIT---

You can also consider using the timeout property for the TestNg suite, you will have to move all your tests to TestNg though, but this will allow you to specify timeouts for groups.

This is the official api documentation: http://testng.org/javadoc/org/testng/xml/XmlSuite.html#setTimeOut(java.lang.String)

2 Comments

I can't do this because I have quite big project and huge amount of tests.
Check my edit, I think with testNg you will be able to specify a timeout for an entire suite
0

I once had the same requirement, and since I was using TestNG, I used the "group feature".

If you're stuck with JUnit, try using the tests suite (http://stackoverflow.com/questions/817135/grouping-junit-tests)

1 Comment

You can also just set the timout at the suite level in your testng xml file. <suite name="Integration Suite" time-out="30000">
0

Try to use the junit Ant task with the timeout parameter.

http://ant.apache.org/manual/Tasks/junit.html

EDIT:
Another thing you can do is to use aspectj with someting like that:

public aspect TestTimeoutChecker { long TIMEOUT = 60000; pointcut invokeEvent() : execution(@Test * *(..)); Object around() : invokeEvent() { long start = System.currentTimeMillis(); Object object = proceed(); long took = System.currentTimeMillis() - start; if (took > TIMEOUT) { throw new RuntimeException("timeout! it took:" + took); } return object; } } 

1 Comment

I considered it, but requires fork mode - which is unacceptable in large projects

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.