JUnit4中@Before不作用于@ParameterizedTest的原因及无侵入解决方案咨询
JUnit4中@Before不作用于@ParameterizedTest的原因及无侵入解决方案咨询
哎,这个问题其实是你混用了JUnit 4和JUnit Jupiter(也就是JUnit 5)的注解体系导致的,我给你掰扯清楚,再给你几个不破坏测试独立性的解决方案:
为什么@Before对@ParameterizedTest不生效?
@Before是JUnit 4的生命周期注解,只会对JUnit 4原生的@Test方法生效;而@ParameterizedTest是JUnit Jupiter(JUnit 5)才引入的参数化测试注解,这俩属于完全不同的测试框架分支,JUnit 4的注解处理器根本识别不了JUnit 5的@ParameterizedTest,自然不会为它执行@Before标注的前置方法。而且你代码里还同时导入了JUnit 4和JUnit 5的包,这种混用本身就容易出问题哦。
不破坏测试独立性的解决方案
方案1:统一切换到JUnit Jupiter(推荐)
直接把JUnit 4的注解换成JUnit Jupiter的对应注解,这样就能完美兼容参数化测试,还能保证每个测试用例(包括参数化的每个参数实例)的独立性:
- 把
@Before换成JUnit Jupiter的@BeforeEach(每个测试方法执行前都会跑一遍,包括参数化的每个参数) - 把JUnit 4的
@Test换成JUnit Jupiter的@Test(注意包路径是org.junit.jupiter.api.Test) - 断言也换成JUnit Jupiter的
assertTrue(包路径org.junit.jupiter.api.Assertions)
修改后的代码如下:
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.assertTrue; public class MyBasicTest { boolean valueIsSetup = false; @BeforeEach public void setup() { valueIsSetup = true; } @Test public void testUsingValue() throws Exception { assertTrue(valueIsSetup); } @ParameterizedTest @ValueSource(booleans = {true, false}) public void parametrizedUsingValue(boolean testValue) throws Exception { assertTrue(valueIsSetup); } }
JUnit Jupiter默认会为每个测试用例创建一个新的测试类实例,完全不用担心变量污染,完美保证测试独立性。
方案2:用JUnit 4原生的参数化测试(不推荐,仅用于无法升级JUnit的场景)
如果因为某些限制必须留在JUnit 4体系,可以用JUnit 4原生的参数化测试方式,配合@Before就能实现需求:
- 用
@RunWith(Parameterized.class)标注测试类 - 通过构造方法传递参数
- 用
@Parameterized.Parameters提供测试数据
代码示例:
import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.util.Arrays; import java.util.Collection; import static org.junit.Assert.assertTrue; @RunWith(Parameterized.class) public class MyBasicTest { boolean valueIsSetup = false; private boolean testValue; // 通过构造方法接收参数 public MyBasicTest(boolean testValue) { this.testValue = testValue; } // 提供参数化测试数据 @Parameterized.Parameters public static Collection<Object[]> data() { return Arrays.asList(new Object[][]{{true}, {false}}); } @Before public void setup() { valueIsSetup = true; } @Test public void testUsingValue() throws Exception { assertTrue(valueIsSetup); } @Test public void parametrizedUsingValue() throws Exception { assertTrue(valueIsSetup); } }
这种方式下,JUnit 4会为每个参数创建一个测试类实例,@Before会在每个实例的测试方法前执行,也能保证测试独立性,但参数化写法比JUnit Jupiter繁琐很多。
备注:内容来源于stack exchange,提问作者Tomáš Zato
相关产品推荐
相关产品推荐

