206

I want to write test cases for a bulk of code, I would like to know details of JUnit @Rule annotation feature, so that I can use it for writing test cases. Please provide some good answers or links, which give detailed description of its functionality through a simple example.

gvlasov
  • 14,781
  • 17
  • 61
  • 99
Dipak
  • 5,512
  • 6
  • 50
  • 78
  • i already gone through this link [http://cwd.dhemery.com/2011/01/what-junit-rules-are-good-for/](http://cwd.dhemery.com/2011/01/what-junit-rules-are-good-for/) – Dipak Nov 21 '12 at 08:46
  • 1
    I think it is similar to the concept of injection, am I right? – Chao Mar 04 '15 at 05:52
  • I found [this article](http://cwd.dhemery.com/2010/12/junit-rules/) explains `@Rule`s rather well, especially check out the last section "The Sequence Of Events In Detail" – Peter Perháč Feb 04 '14 at 15:35
  • Thanks for sharing that link. One thing is not clear. When does the DEFAULT Statement.evaluate() get called ? Is it called before the evaluate() of all rules or after all of them ? I am guessing after all of them. – MasterJoe Jul 25 '18 at 02:42
  • @testerjoe2 you may choose to ignore the default Statement completely. You may choose to delegate to it or you may simply replace it altogether with some other Statement of your own. It doesn't _get called_, _you_ may call it or not. That was in point 10: "The screenshot statement’s evaluate() method calls the default statement’s evaluate() method." – Peter Perháč Jul 25 '18 at 08:39
  • I came here to understand how "RetryRuleTest" works with a custom Rule. Its from the Junit & mockito book which you also read. Code - https://github.com/tomekkaczanowski/junit-put-examples/tree/master/src/test/java/com/practicalunittesting/chp06/rules/custom . Does it work like this ? (1) Junit creates a default Statement and calls its evaluate() to run the test method. Then, Junit calls the apply() method of the first (and only) rule. Junit runs evaluate() of the Statement returned by rule. End of story. – MasterJoe Jul 25 '18 at 17:22

4 Answers4

161

Rules are used to add additional functionality which applies to all tests within a test class, but in a more generic way.

For instance, ExternalResource executes code before and after a test method, without having to use @Before and @After. Using an ExternalResource rather than @Before and @After gives opportunities for better code reuse; the same rule can be used from two different test classes.

The design was based upon: Interceptors in JUnit

For more information see JUnit wiki : Rules.

MasterJoe
  • 1,280
  • 3
  • 17
  • 46
Matthew Farwell
  • 58,043
  • 17
  • 119
  • 166
  • 1
    Correction: "For instance, ExternalResource executes code before and after a test *class*." There's something about using apply() to get the ExternalResource to run between tests. – derekm Jul 12 '16 at 17:14
  • Reading [this](https://www.codeaffine.com/2012/09/24/junit-rules/) helped me to understand `ExternalResource` mentioned in the answer. – jumping_monkey Jan 13 '21 at 06:51
66

Junit Rules work on the principle of AOP (aspect oriented programming). It intercepts the test method thus providing an opportunity to do some stuff before or after the execution of a particular test method.

Take the example of the below code:

public class JunitRuleTest {

  @Rule
  public TemporaryFolder tempFolder = new TemporaryFolder();

  @Test
  public void testRule() throws IOException {
    File newFolder = tempFolder.newFolder("Temp Folder");
    assertTrue(newFolder.exists());
  }
} 

Every time the above test method is executed, a temporary folder is created and it gets deleted after the execution of the method. This is an example of an out-of-box rule provided by Junit.

Similar behaviour can also be achieved by creating our own rules. Junit provides the TestRule interface, which can be implemented to create our own Junit Rule.

Here is a useful link for reference:

StefanR
  • 458
  • 4
  • 12
  • 4
    so it gets deleted without writing any code to delete/clear the object ? – Dror Aug 22 '16 at 04:44
  • look at the source of https://github.com/junit-team/junit4/blob/master/src/main/java/org/junit/rules/TemporaryFolder.java , the folder is created in the before() callback method and deleted in the after() callback method ... – Pierluigi Vernetto Dec 03 '17 at 09:30
  • 1
    For people who might have not understood why the TemporaryFolder gets deleted it is because it's a TemporaryFolder provided by Junit to serve as a temp folder that gets automatically deleted - i.e. the teardown step is part of the TemporaryFolder class itself. – Mindaugas Bernatavičius Jun 29 '19 at 04:40
  • Upvoted for the useful link, thanks. – jumping_monkey Jan 13 '21 at 06:52
18

The explanation for how it works:

JUnit wraps your test method in a Statement object so statement and Execute() runs your test. Then instead of calling statement.Execute() directly to run your test, JUnit passes the Statement to a TestRule with the @Rule annotation. The TestRule's "apply" function returns a new Statement given the Statement with your test. The new Statement's Execute() method can call the test Statement's execute method (or not, or call it multiple times), and do whatever it wants before and after.

Now, JUnit has a new Statement that does more than just run the test, and it can again pass that to any more rules before finally calling Execute.

Ashish Karn
  • 1,074
  • 1
  • 9
  • 20
Alexander Taylor
  • 13,171
  • 10
  • 56
  • 75
0

Rules are used to enhance the behaviour of each test method in a generic way. Junit rule intercept the test method and allows us to do something before a test method starts execution and after a test method has been executed.

For example, Using @Timeout rule we can set the timeout for all the tests.

public class TestApp {
    @Rule
    public Timeout globalTimeout = new Timeout(20, TimeUnit.MILLISECONDS);

    ......
    ......

 }

@TemporaryFolder rule is used to create temporary folders, files. Every time the test method is executed, a temporary folder is created and it gets deleted after the execution of the method.

public class TempFolderTest {

 @Rule
 public TemporaryFolder tempFolder= new TemporaryFolder();

 @Test
 public void testTempFolder() throws IOException {
  File folder = tempFolder.newFolder("demos");
  File file = tempFolder.newFile("Hello.txt");

  assertEquals(folder.getName(), "demos");
  assertEquals(file.getName(), "Hello.txt");

 }


}

You can see examples of some in-built rules provided by junit at this link.

Hari Krishna
  • 2,599
  • 19
  • 37