当@ Rule的相互依赖时,如何处理它们的排序

Len*_*din 32 java junit junit4

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

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

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

如果我颠倒了我的类中的属性的顺序,我得到一个编译错误,因为我无法在定义之前引用变量.

我正在使用Junit 4.8.1(因为4.7版本中的规则排序有点固定)

Mat*_*ell 42

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

您可以在没有@Rule注释的情况下引入另一个私有字段,然后您可以根据需要重新排序代码:

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());
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

最干净的解决方案是有一个复合规则,但上述应该有效.

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

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);
   }
}
Run Code Online (Sandbox Code Playgroud)

写日志

starting outer rule
starting middle rule
starting inner rule
finished inner rule
finished middle rule
finished outer rule
Run Code Online (Sandbox Code Playgroud)

  • 没有任何东西可以阻止您将规则声明为类中的私有字段,然后在RuleChain中使用它.然后,您可以在测试中访问它 (4认同)

Ger*_*cke 7

要使规则依赖,您必须首先初始化它们并使用构造函数或(根据您的规则)流畅的构建器创建依赖关系.必须在字段初始化中定义依赖关系,并且不能在@Before方法中创建依赖关系,因为这些在规则应用之后执行.要强制正确排序规则,必须定义规则链.

public class FolderRuleOrderingTest {

  private TemporaryFolder folder = new TemporaryFolder();
  //assume, we have a rule that creates a testfile in a temporary folder
  //we create a dependency relationship between file and folder,
  //so that file depends on folder
  private TemporaryFile file = new TemporaryFile(folder, "testfile.txt");

  //the rule chain ensures, the temporary folder is created before and removed 
  //after the testfile has been created and deleted (or whatever)
  @Rule
  public RuleChain chain= RuleChain.outerRule(folder).around(file));


  @Test
  public void testFileExist() throws IOException {
    assertTrue(file.getFile().exist());
  }
  ...
}
Run Code Online (Sandbox Code Playgroud)


Ha.*_*Ha. 3

如果您找不到正常的解决方案,您始终可以创建@Rule包含所有其他规则的复合规则(也是唯一一个带有注释的规则)并按顺序执行它们。