【问题标题】:What does @Rule do?@Rule 有什么作用?
【发布时间】:2015-07-22 22:37:16
【问题描述】:

在尝试为单元测试制作临时文件时,我遇到了this answer,其中提到了“TemporaryFolder JUnit @Rule”,还有一个link 解释了如何使用它。是这样的:

@Rule
public TemporaryFolder testFolder = new TemporaryFolder();

然后testFolder.newFile("file.txt")

我的问题是@Rule 注解有什么作用?

删除注释似乎并没有真正改变任何东西。

【问题讨论】:

    标签: java junit rule


    【解决方案1】:

    正如RuleTemporaryFolder 的文档所述,它负责在各个​​类的每个测试方法之前创建一个临时目录,并在每个测试方法之后删除这个临时文件夹(及其内容)。

    您可以通过实现TestRuleMethodRule 或从其任何实现类(如ExternalResource)扩展来轻松编写自己的规则。

    @Before@After 带注释的初始化和清理方法可以保证相同的逻辑。但是,您需要将逻辑直接添加到测试类中。如果您需要多个测试类中的逻辑,则需要使用继承、编写一些任意实用程序类或将行为外部化。规则通过允许您重新使用这种初始化或清理逻辑并进一步减少代码并删除不需要的代码来完成后一个,因此重点是实际测试而不是某些目录或服务器的配置。

    This project 例如声明了两种服务器(Jetty 或 Tomcat),您只需使用 @Rule 进行注释,以便将服务器用于集成或端到端测试。

    如果您只想为所有测试方法初始化一次规则,只需将@Rule 替换为@ClassRule 并将规则初始化为public static。这将只初始化一次类规则,并将在每个测试方法中重复使用。

    @ClassRule
    public static JettyServerRule server = new JettyServerRule(new EmbeddedJetty());
    
    @Test
    public void myUnitTest() {
        RestTemplate restTemplate = new RestTemplate();
        String url = String.format("http://localhost:%s", server.getPort());
    
        String response = restTemplate.getForObject(url, String.class);
    
        assertEquals("Hello World", response);
    }
    

    上面的示例将只初始化一个 Jetty 服务器一次,并且测试类的每个测试方法都可以重用这个服务器,而不是为每个方法启动和拆除一个新的服务器。

    多个规则甚至可以与RuleChain组合:

    @Rule
    public RuleChain chain= RuleChain.outerRule(new LoggingRule("outer rule")
                                     .around(new LoggingRule("middle rule")
                                     .around(new LoggingRule("inner rule");
    

    在我们的一个集成测试中,它同时向通过 Jetty 上的 Restlet 部署的 JAX-RS 服务发送了几个请求,我们有以下规则定义:

    public static SpringContextRule springContextRule;
    public static RestletServerRule restletServer;
    
    static {
        springContextRule = new SpringContextRule(JaxRsRestletTestSpringConfig.class);
        restletServer = new RestletServerRule(springContextRule.getSpringContext());
    }
    
    @ClassRule
    public static RuleChain ruleChain = RuleChain.outerRule(restletServer).around(springContextRule);
    
    // Tempus Fugit rules
    @Rule
    public ConcurrentRule concurrently = new ConcurrentRule();
    
    @Rule
    public RepeatingRule repeatedly = new RepeatingRule();
    

    在 Restlet/Jetty 服务器启动之前初始化一个 spring 注释上下文以启用 Spring bean 注入。此外,Tempus Fugit 规则用于同时执行几次测试方法,以便更早地发现竞争条件和并发相关问题。

    【讨论】:

      猜你喜欢
      • 2013-01-07
      • 2022-01-27
      • 2020-02-14
      • 2015-12-04
      • 1970-01-01
      • 1970-01-01
      • 2021-02-03
      • 2014-02-26
      • 2023-04-10
      相关资源
      最近更新 更多