Как получить доступ к полям тестового класса с помощью правила в JUnit
Я хочу написать JUnit @Rule (версия 4.10), чтобы настроить некоторые объекты (Entity Manager) и сделать их доступными в тесте, путем "впрыскивания" его в переменную.
Что-то вроде этого:
public class MyTestClass() {
@Rule
MyEntityManagerInjectRule = new MyEntityManagerInjectRule():
//MyEntityManagerInjectRule "inject" the entity manager
EntityManger em;
@Test...
}
Проблема в том, что я не знаю, как получить текущий экземпляр MyTestClass
в MyEntityManagerInjectRule (расширяет TestRule), потому что он имеет только один метод.
Statement apply(Statement base, Description description);
Внутри описания есть только класс MyTestClass, но не экземпляр, используемый для теста.
Альтернативой будет использование org.junit.rules.MethodRule, но это устарело.
До и после недостаточно для этой задачи, потому что тогда мне нужно будет скопировать код в тесты, и они более или менее устарели. (См. Block4JClassRunner.withBefores/withAfters).
Итак, мой вопрос в том, как я могу получить доступ к экземпляру тестового класса без использования устаревшего материала.
Ответы
Ответ 1
Как насчет:
public class MyTestClass() {
@Rule
public TestRule MyEntityManagerInjectRule =
new MyEntityManagerInjectRule(this); // pass instance to constructor
//MyEntityManagerInjectRule "inject" the entity manager
EntityManger em;
@Test...
}
Просто добавьте экземпляр тестового класса в конструктор для @Rule
. Просто будьте осторожны с порядком назначения.
Ответ 2
Правильный способ добиться этого - сделать ваше правило реализацией org.junit.rules.MethodRule
(not TestRule
). Метод apply()
интерфейса MethodRule
имеет аргумент target
, который содержит ссылку на текущий экземпляр тестового класса (конечно, это другой экземпляр каждый раз, когда метод выполняется).
Пример 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()");
}
}
};
}
}
Пример тестового класса с использованием @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()");
}
}
Ответ 3
Существует другой подход: правило предоставляет EntityManager вместо того, чтобы вводить его.
public class MyTestClass() {
@Rule
public MyEntityManagerRule rule = new MyEntityManagerRule();
@Test
public void firstTest() {
doSomethingWith(rule.getEntityManager());
}
}