相互依赖时如何处理@Rule的顺序 [英] How to handle ordering of @Rule's when they are dependent on each other

查看:155
本文介绍了相互依赖时如何处理@Rule的顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用在Junit测试用例中运行的嵌入式服务器.有时,这些服务器需要一个工作目录(例如Apache Directory服务器).

I use embedded servers that run inside Junit test cases. Sometimes these servers require a working directory (for example the Apache Directory server).

Junit 4.7中的新@Rule可以处理这些情况. TemporaryFolder-Rule可以创建一个临时目录.可以为服务器创建自定义的ExternalResource-Rule.但是,如果我想将结果从一个规则传递到另一个规则,该如何处理:

The new @Rule in Junit 4.7 can handle these cases. The TemporaryFolder-Rule can create a temporary directory. A custom ExternalResource-Rule can be created for server. But how do I handle if I want to pass the result from one rule into another:

import static org.junit.Assert.assertEquals;
import java.io.*;
import org.junit.*;
import org.junit.rules.*;

public class FolderRuleOrderingTest {

    @Rule
    public TemporaryFolder folder = new TemporaryFolder();

    @Rule
    public MyNumberServer server = new MyNumberServer(folder);

    @Test
    public void testMyNumberServer() throws IOException {
        server.storeNumber(10);
        assertEquals(10, server.getNumber());
    }

    /** Simple server that can store one number */
    private static class MyNumberServer extends ExternalResource {

        private TemporaryFolder folder;

        /** The actual datafile where the number are stored */
        private File dataFile;

        public MyNumberServer(TemporaryFolder folder) {
            this.folder = folder;
        }

        @Override
        protected void before() throws Throwable {
            if (folder.getRoot() == null) {
                throw new RuntimeException("TemporaryFolder not properly initialized");
            }

            //All server data are stored to a working folder
            File workingFolder = folder.newFolder("my-work-folder");
            dataFile = new File(workingFolder, "datafile");
        }

        public void storeNumber(int number) throws IOException {
            dataFile.createNewFile();
            DataOutputStream out = new DataOutputStream(new FileOutputStream(dataFile));
            out.writeInt(number);
        }

        public int getNumber() throws IOException {
            DataInputStream in = new DataInputStream(new FileInputStream(dataFile));
            return in.readInt();
        }
    }
}

在此代码中,文件夹作为参数发送到服务器,以便服务器可以创建工作目录来存储数据.但是,这不起作用,因为Junit以文件中定义的相反顺序处理规则. TemporaryFolder规则将在服务器规则之前不执行.因此,TempraryFolder中的根文件夹将为空,从而导致相对于当前工作目录创建任何文件.

In this code the folder is sent as a parameter into the server so that the server can create a working directory to store data. However this does not work because Junit processes the rules in reverse order as they are defined in the file. The TemporaryFolder Rule will not be executed before the server Rule. Thus the root-folder in TempraryFolder will be null, resulting that any files are created relative to the current working directory.

如果我颠倒了类中属性的顺序,则会出现编译错误,因为在定义变量之前我无法引用它.

If I reverse the order of the attributes in my class I get a compile error because I cannot reference a variable before it is defined.

我使用的是Junit 4.8.1(因为从4.7版本开始,规则的顺序已得到固定)

I'm using Junit 4.8.1 (because the ordering of rules was fixed a bit from the 4.7 release)

推荐答案

使用最近发布的Junit 4.10,您可以使用RuleChain正确地链接规则(请参见最后).

With the recently released Junit 4.10, you can use RuleChain to chain rules correctly (see at the end).

您可以引入另一个没有@Rule批注的私有字段,然后可以根据需要对代码进行重新排序:

You could introduce another private field without the @Rule annotation, then you can reorder your code as you wish:

public class FolderRuleOrderingTest {

    private TemporaryFolder privateFolder = new TemporaryFolder();

    @Rule
    public MyNumberServer server = new MyNumberServer(privateFolder);

    @Rule
    public TemporaryFolder folder = privateFolder;

    @Test
    public void testMyNumberServer() throws IOException {
        server.storeNumber(10);
        assertEquals(10, server.getNumber());
    }
    ...
}

最干净的解决方案是采用复合规则,但以上方法应该可以工作.

The cleanest solution is to have a compound rule, but the above should work.

使用最近发布的Junit 4.10,您可以使用RuleChain正确地链接规则:

With the recently released Junit 4.10, you can use RuleChain to chain rules correctly:

public static class UseRuleChain {
   @Rule
   public TestRule chain = RuleChain
                          .outerRule(new LoggingRule("outer rule"))
                          .around(new LoggingRule("middle rule"))
                          .around(new LoggingRule("inner rule"));

   @Test
   public void example() {
           assertTrue(true);
   }
}

写日志

starting outer rule
starting middle rule
starting inner rule
finished inner rule
finished middle rule
finished outer rule

这篇关于相互依赖时如何处理@Rule的顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆