简体   繁体   中英

How to access the fields of a test class with in an Rule in JUnit

I want to write an JUnit @Rule (version 4.10) to setup some objects (an Entity Manager) and make them available in the test, by "injecting" it into an variable.

Something like this:

public class MyTestClass() {

  @Rule
  MyEntityManagerInjectRule = new MyEntityManagerInjectRule():

  //MyEntityManagerInjectRule "inject" the entity manager
  EntityManger em;

  @Test...
}

The Problem is that I do not know how to get the current instance of MyTestClass in the MyEntityManagerInjectRule (extends TestRule), because it has only one method. Statement apply(Statement base, Description description);

Within Description there is only the class MyTestClass but not the instance used for the test.

An alternative would be using org.junit.rules.MethodRule but this is deprecated. Before and After are not sufficient for this task, because then I would need to copy the code to the tests, and they are more or less deprecated too. (See Block4JClassRunner.withBefores / withAfters).

So my question in how could I access the test class instance without using deprecated stuff.

The proper way to achieve that is to make your rule implement org.junit.rules.MethodRule (not TestRule ). The apply() method of the MethodRule interface has a target argument, which holds a reference to the current instance of the test class (of course, it is a different instance each time a method is executed).

Example MethodRule

public class ExampleMethodRule implements MethodRule {

    @Override
    public Statement apply(final Statement base,
                                         FrameworkMethod method, Object target) {
        System.out.println("ExampleMethodRule#apply()" +
                           "\n\t base: " + base +
                           "\n\t method (current test method): " + method +
                           "\n\t target (current test class instance): "+target);

        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                System.out.println("->before evaluate()");
                try {
                    base.evaluate();
                } finally {
                    System.out.println("->after evaluate()");
                }
            }
        };
    }
}

Example test class using @Rule

public class ExampleTest {

    @Rule
    public ExampleMethodRule exampleMethodRule = new ExampleMethodRule();

    @BeforeClass
    public static void beforeClass() {
        System.out.println("@BeforeClass");
    }
    @AfterClass
    public static void afterClass() {
        System.out.println("@AfterClass");
    }

    @Before
    public void before() {
        System.out.println("@Before");
    }
    @After
    public void after() {
        System.out.println("@After");
    }

    @Test
    public void aa() {
        System.out.println("method aa()");
    }
    @Test
    public void bb() {
        System.out.println("method bb()");
    }

}

How about:

public class MyTestClass() {
  @Rule
  public TestRule MyEntityManagerInjectRule =
         new MyEntityManagerInjectRule(this); // pass instance to constructor

  //MyEntityManagerInjectRule "inject" the entity manager
  EntityManger em;

  @Test...
}

Just add the test class instance to the constructor for the @Rule . Just be careful of the order of assignment.

There is a different approach: the rule provides the EntityManager instead of injecting it.

public class MyTestClass() {
  @Rule
  public MyEntityManagerRule rule = new MyEntityManagerRule();

  @Test
  public void firstTest() {
     doSomethingWith(rule.getEntityManager());
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM