@After和@Before在测试用例中无效。

47

我已经开始测试了,现在我想使用 @After@Before@Test,但是我的应用程序只运行 @Before 方法并在控制台上输出。

before

然而,如果我移除 @After@Before,它会运行 @Test。我的代码在这里:

public class TestPractise extends AbstractTransactionalDataSourceSpringContextTests{

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

    @Test
    public void testingMethod(){
        System.out.println("testing");
    }

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

为什么@After@Test@Before不能同时工作?

8个回答

73

使用@BeforeEach替代@Before,并使用@AfterEach替代@After


9
你能否加上一点关于为什么以及如何解决这个问题的解释? - anothernode
3
在我的情况下,我的“@Before”和“@After”代码没有运行,但当我用“@BeforeEach”替换“@Before”,并使用“@After”和“@AfterEach”时,它就起作用了。 - vikram k
这只是更具体的名称,工作方式相同。但支持(执行)取决于 Junit 版本。 - vikram k
2
老兄!我花了好几个小时才搞明白这个问题! - sschrass
1
请记住,这会创建大量浪费的执行。BeforeEach 会在每次运行测试之前重置所有内容。这可能是可取的,但对于例如为测试参数加载文件或一次性文件读取类时则是不必要的。 - avgvstvs

21

AbstractTransactionalDataSourceSpringContextTests类强制使用旧的JUnit 3.x语法,这意味着任何JUnit 4注释都不起作用。

您的runBare()方法的执行并不是因为@Before注释,而是因为它命名为runBare(),这是由ConditionalTestCase和JUnit TestCase类提供的方法。

因此,您有两个解决方案:

  • 使用AlexR的答案来使用JUnit 4测试和Spring;
  • 保留继承AbstractTransactionalDataSourceSpringContextTests,但使用onSetUponTearDown方法代替@Before@After方法。

1
遇到了混用 JUnit 4 和 5 的相同问题。检查你的注解导入并确保它们匹配。 - Muhd

19

请检查您是否使用Junit4,因为在Junit5及以后,@Before / @After现在是@BeforeEach / @AfterEach,同样的@BeforeClass / @AfterClass是@AfterAll / @BeforeAll。


7
它应该能够正常工作...但是由于您正在使用Spring框架,而JUnit 4已经推出多年了,我建议您使用注解代替继承。
因此,请使用@RunWith(SpringJUnit4ClassRunner.class)为您的类进行注释。删除extends AbstractTransactionalDataSourceSpringContextTests
不要忘记将@Before和@After方法static
现在它应该能够正常工作。
即使您想扩展Spring抽象测试类,也请注意其中一些已被弃用。例如,AbstractTransactionalDataSourceSpringContextTests类已被弃用。

你能否给我提供一个 @RunWith(SpringJUnit4ClassRunner.class) 的例子? - abhishek ameta
如果您能为AbstractTransactionalDataSourceSpringContextTests编写一个示例,那将非常好。 - abhishek ameta
抱歉耽搁了。这个例子非常简单。只需删除“extends…”并将我写的注释添加到类中。然后尝试运行测试。 - AlexR

6

JUnit Jupiter,又称“JUnit 5”:使用@BeforeAll

如果你使用更新的JUnit Jupiter(从Java 8开始),你需要用@BeforeAll替换@Before

此外,你需要给测试类注解上@TestInstance(Lifecycle.PER_CLASS)或者将@BeforeAll方法声明为static。下面是一个例子:

@TestInstance(Lifecycle.PER_CLASS)
class MyTestClass {

    MyHeavyResource sharedResource;

    @BeforeAll
    void init() {
        System.out.println("init");
        sharedResource = new MyHeavyResource(1234);
    }

    @Test
    void myTest() {
        System.out.println("myTest");
        sharedResource.methodUnderTest();
    }
}

理解Lifecycle.PER_CLASS

Junit 5更加严格地要求在@BeforeAll方法中初始化的任何资源实例必须使用staticLifecycle.PER_CLASS修饰符,这是为了让测试作者知道该资源实例会在类内每个单元测试方法中共享,并可能威胁到测试用例的隔离性,例如如果上面示例中的sharedResource不是无状态/幂等的。

如果sharedResource不能安全地共享(或者它足够轻量级),则应该使用@BeforeEach修饰符来注释init方法,在执行类内每个单元测试之前创建一个新实例。

TestInstance的Javadoc解释了如何使用Lifecycle.PER_CLASS可以强制执行单个测试类的单个实例。而JUnit 4及更早版本的行为相当于Lifecycle.PER_METHOD,即为其中每个@Test方法创建一个新的测试类实例。这将误导作者认为@Before仅对这些测试之一执行一次。


3
如果您在IDE中使用自动导入功能,请确保从org.junit包导入@Test@Before

0
在我的情况下,我遇到了这个问题,解决方法是更改Java访问修饰符,它原来是私有的。
之前(不工作) @Test void validate() throws Exception {}
之后(工作) @Test public void validate() throws Exception {}

0
  • 在我的情况下,我只是将@Before / @BeforeEach注释的setUp()方法中的内容移动到单元测试类的构造函数中。
  • 根据this thread,使用构造函数相当于使用@Before方法

我无法解释为什么它可以解决问题,但我在一个特定的类中遇到了这个问题,它确实奏效了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接