Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid inheritance in JUnit test cases?

Tags:

java

junit

I have a number of test cases in JUnit. All of them need the same code to be executed in their @BeforeClass static method. It's a code duplication and I'm trying to get rid of it. A dirty way of doing this is by inheritance. Are there any other mechanisms in JUnit, that may help?

PS. I wrote this blog post about this very subject: http://www.yegor256.com/2015/05/25/unit-test-scaffolding.html

like image 748
yegor256 Avatar asked Jul 16 '11 04:07

yegor256


People also ask

When should you not use inheritance?

Inheritance creates dependency between child and parent, when a class inherit another class, we include all methods and attributes from parent class and expose to the child class, therefore we break the encapsulation, the child object can access all the methods in parent object and overwrite them.

Should JUnit tests throw exceptions?

The JUnit TestRunners will catch the thrown Exception regardless so you don't have to worry about your entire test suite bailing out if an Exception is thrown. This is the best answer.

How do you exclude a test in JUnit?

If you want to ignore a test method, use @Ignore along with @Test annotation. If you want to ignore all the tests of class, use @Ignore annotation at the class level.

What does @ignore do in JUnit?

A test method annotated with @Ignore will not be executed. If a test class is annotated with @Ignore, then none of its test methods will be executed.


2 Answers

The JUnit way to compose reusable code (instead of inheriting from it) are Rules.

See https://github.com/junit-team/junit/wiki/Rules

Here is a dumb sample, but you'll get the point.

import org.junit.rules.TestRule; import org.junit.runners.model.Statement; import org.junit.runner.Description;  public class MyTestRule implements TestRule {   @Override   public Statement apply(final Statement statement, Description description) {     return new Statement() {       public void evaluate() throws Throwable {         // Here is BEFORE_CODE         try {           statement.evaluate();         } finally {           // Here is AFTER_CODE         }       }     };   } } 

You can then use your TestRule like this:

import org.junit.Rule;  public class MyTest {     @Rule     public MyTestRule myRule = new MyTestRule(); } 

BEFORE_CODE and AFTER_CODE will then be executed around each of your test methods.

If you need to run your code only once per class, use your TestRule as a @ClassRule:

import org.junit.ClassRule;  public class MyTest {     @ClassRule     public static MyTestRule myRule = new MyTestRule(); } 

Now, BEFORE_CODE and AFTER_CODE will be executed around each of your test class.

@Rule field is not static, @ClassRule field is.

A @ClassRule can be declared in a Suite too.

Note that you can declare several rules in a single test class, that's how you compose test lifecycles at test-suites, test-classes and test-methods levels.

A Rule is an object that you instanciate in your test classes (statically or not). You can add contructor parameters if needed.

HTH

like image 54
eskatos Avatar answered Oct 02 '22 20:10

eskatos


If the method is some kind of utility, then separate it out to a different class with a static method and call that method in your @BeforeClass.

I emphasize on the fact that don't use inheritance just because it solves your problem, use it when doing so creates sense in your class hierarchy.

like image 27
Suraj Chandran Avatar answered Oct 02 '22 18:10

Suraj Chandran