在JUnit 3中,我可以像这样获得当前运行的测试的名称:
public class MyTest extends TestCase
{
public void testSomething()
{
System.out.println("Current test is " + getName());
...
}
}
它会打印“当前测试是testSomething”。
在JUnit 4中是否有任何开箱即用或简单的方法来做到这一点?
背景:显然,我不想只打印测试的名称。我希望加载存储在与测试同名的资源中的特定于测试的数据。你知道,约定比配置更重要。
一种复杂的方法是通过子类化org.junit.runners.BlockJUnit4ClassRunner来创建自己的Runner。
然后你可以这样做:
public class NameAwareRunner extends BlockJUnit4ClassRunner {
public NameAwareRunner(Class<?> aClass) throws InitializationError {
super(aClass);
}
@Override
protected Statement methodBlock(FrameworkMethod frameworkMethod) {
System.err.println(frameworkMethod.getName());
return super.methodBlock(frameworkMethod);
}
}
然后,对于每个测试类,您需要添加一个@RunWith(nameawarerener .class)注释。或者,如果不想每次都记住它,也可以将该注释放在Test超类上。当然,这限制了跑步者的选择,但这可能是可以接受的。
此外,将当前测试名称从Runner中取出并放入框架可能需要一些功夫,但这至少为您提供了名称。
试试这个吧:
public class MyTest {
@Rule
public TestName testName = new TestName();
@Rule
public TestWatcher testWatcher = new TestWatcher() {
@Override
protected void starting(final Description description) {
String methodName = description.getMethodName();
String className = description.getClassName();
className = className.substring(className.lastIndexOf('.') + 1);
System.err.println("Starting JUnit-test: " + className + " " + methodName);
}
};
@Test
public void testA() {
assertEquals("testA", testName.getMethodName());
}
@Test
public void testB() {
assertEquals("testB", testName.getMethodName());
}
}
输出如下所示:
Starting JUnit-test: MyTest testA
Starting JUnit-test: MyTest testB
注意:如果你的测试是TestCase的子类,这是行不通的!测试运行了,但是@Rule代码从来没有运行过。
基于前面的评论,并进一步考虑我创建了一个TestWather的扩展,你可以在你的JUnit测试方法中使用:
public class ImportUtilsTest {
private static final Logger LOGGER = Logger.getLogger(ImportUtilsTest.class);
@Rule
public TestWatcher testWatcher = new JUnitHelper(LOGGER);
@Test
public test1(){
...
}
}
测试助手类是下一个:
public class JUnitHelper extends TestWatcher {
private Logger LOGGER;
public JUnitHelper(Logger LOGGER) {
this.LOGGER = LOGGER;
}
@Override
protected void starting(final Description description) {
LOGGER.info("STARTED " + description.getMethodName());
}
@Override
protected void succeeded(Description description) {
LOGGER.info("SUCCESSFUL " + description.getMethodName());
}
@Override
protected void failed(Throwable e, Description description) {
LOGGER.error("FAILURE " + description.getMethodName());
}
}
享受吧!
在JUnit 5中,TestInfo代替了JUnit 4中的TestName规则。
从文档中可以看到:
TestInfo用于注入有关当前测试的信息
容器到@Test, @RepeatedTest, @ParameterizedTest,
@TestFactory, @BeforeEach, @AfterEach, @BeforeAll和@AfterAll
方法。
要检索当前执行测试的方法名,您有两个选项:String TestInfo.getDisplayName()和
TestInfo.getTestMethod()方法。
仅检索当前测试方法的名称TestInfo.getDisplayName()可能不够,因为测试方法的默认显示名称是methodName(TypeArg1, TypeArg2,…TypeArg3)。
在@DisplayName("..")中复制方法名并不一定是个好主意。
作为你可以使用的替代方案
返回一个Optional<Method>对象的TestInfo.getTestMethod()。
如果在测试方法中使用检索方法,则甚至不需要测试Optional包装值。
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.Test;
@Test
void doThat(TestInfo testInfo) throws Exception {
Assertions.assertEquals("doThat(TestInfo)",testInfo.getDisplayName());
Assertions.assertEquals("doThat",testInfo.getTestMethod().get().getName());
}
JUnit 5通过ExtensionContext
优势:
您可以通过重写afterEach(ExtensionContext上下文)来获得ExtensionContext的附加功能。
public abstract class BaseTest {
protected WebDriver driver;
@RegisterExtension
AfterEachExtension afterEachExtension = new AfterEachExtension();
@BeforeEach
public void beforeEach() {
// Initialise driver
}
@AfterEach
public void afterEach() {
afterEachExtension.setDriver(driver);
}
}
public class AfterEachExtension implements AfterEachCallback {
private WebDriver driver;
public void setDriver(WebDriver driver) {
this.driver = driver;
}
@Override
public void afterEach(ExtensionContext context) {
String testMethodName = context.getTestMethod().orElseThrow().getName();
// Attach test steps, attach scsreenshots on failure only, etc.
driver.quit();
}
}
更简单的方法是将此逻辑放在setUp()和tearDown()方法中。
参考下面的代码,以获得更好的清晰度,
import java.lang.reflect.Method;
@BeforeMethod
void setUp(Method method) {
log.info("###############################################");
log.info("Running Test: {}", method.getName());
}
@AfterMethod
void tearDown(Method method) {
log.info("Finished Test: {}", method.getName());
log.info("###############################################");
}
@Test
public void testMethodName() {
// Method logic implementation...
}
以下是上述测试执行的输出,
#############################################################
Running Test: testMethodName
// Logs related to method execution...
Finished Test: testMethodName
#############################################################