2010-04-28 69 views
30

我使用在Junit测试用例中运行的嵌入式服务器。有时这些服务器需要一个工作目录(例如Apache Directory服务器)。如何处理@ Rule在彼此依赖时的排序

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(); 
     } 
    } 
} 

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

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

我使用JUnit 4.8.1(因为规则的顺序是固定从4.7版本有点)

+0

排序从4.7到4.8是如何确定的? – zedoo 2014-04-24 08:23:27

回答

3

如果你不会找到正解,你总是可以创建复合规则(也是唯一一个有@Rule注释)包含所有其他并按顺序执行它们。

+0

是的,这将工作。它的缺点是该文件夹不能在测试用例中的其他代码之间轻松共享。 – 2010-05-04 14:02:24

35

编辑:随着最近发布的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()); 
    } 
    ... 
} 

最简洁的解决方案是有一个复合规则,但上面的应该工作。

编辑:随着最近发布的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); 
    } 
} 

写入日志

starting outer rule 
starting middle rule 
starting inner rule 
finished inner rule 
finished middle rule 
finished outer rule 
+0

如果我想要从测试中访问规则,该怎么办?任何方式来访问“链”字段的内容? – Henrik 2015-11-10 14:57:45

+2

没有什么能阻止你在你的类中声明一个规则作为私有字段,然后在RuleChain中使用它。当然,你可以在测试 – 2015-11-11 07:54:22

+1

中使用它。非常简单,我在疯狂搜索课程访问时错过了它。谢谢。 – Henrik 2015-11-11 07:57:27

5

制定规则相关的,您必须对它们进行初始化首先使用构造函数或(根据你的规则)流利的构建者创建依赖关系。依赖关系必须在字段初始化中定义,并且不能在@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()); 
    } 
    ... 
}