【问题标题】:Unit: How to write test case using jUnit and MockitoUnit:如何使用 jUnit 和 Mockito 编写测试用例
【发布时间】:2011-05-17 20:23:44
【问题描述】:

总的来说,我对 Mockito、jUnit 和 TDD 非常陌生,我尝试学习正确的方法来执行 TDD。我需要几个例子来启动我的大脑。所以请帮助我

所以我有一个方法getNameInc(String dirPath, String filenName)。所以给定一个像bankAccount.pdf这样的文件名,如果在这个文件夹中,没有文件名bankAccount.pdf,则返回bankAccountAA.pdf。如果存在一个bankAccount.pdf,那么return bankAccountBB.pdf increment 就是AA-ZZ。当它到达ZZ 时,它会回滚到AA。我已经实现了这个方法的逻辑。如何使用 Mockiti 和 jUnit 对该方法进行单元测试?

编辑

这里是涉及到的类和方法。

public class PProcessor{

    private final Map<Integer, String> incMap = new HashMap<Integer, String>();

    private String getNameInc(String dirPath, String filenName){
         String[] nameList = new File(dirPath).list(new FilenameFilter(){
            public boolean accept(File file, String name) {
                //only load pdf files
                return (name.toLowerCase().endsWith(".pdf"));
            }
        });
        //Return the number of occurance that a given file name appear
        //inside the output folder.
        int freq = 0;
        for(int i=0; i<nameList.length; i++){

            if(fileName.equals(nameList[i].substring(0, 8))){
                freq++;
            }
        }
        return incMap.get(freq);
    }

    private void generateIncHashMap(){
        incMap.put(new Integer(0), "AA");
        incMap.put(new Integer(1), "BB");
        incMap.put(new Integer(2), "CC");
        ...
    }
}

generateIncHashMap()会在构造函数中被调用来预生成哈希映射

【问题讨论】:

  • 我认为你错过了模拟的重点。模拟不应该实现任何逻辑。通常,它只会根据正在使用的测试用例返回硬编码值。
  • @Mike:我已经实现了逻辑。我已经实现了getNameInc(String dirPath, String fileName) 方法。我只是想知道如何对其进行单元测试。它可以是 mockito 或普通的旧 jUnit。我试着学习这个想法。
  • 很高兴您想使用 TDD!但是从您最后的评论中听起来好像您首先编写了逻辑......这与 TDD 的工作方式相反。首先编写一个失败的测试,然后用真实的代码使测试通过,然后重构该代码,使其更简洁,但除了通过测试之外没有任何作用。然后编写另一个失败的测试。 Mockito 可以帮助您排除您的班级所依赖的复杂服务。您能否使用正在协作开发此功能的课程更新您的问题?
  • @alpian:我用一些代码更新了我的帖子。你能看看他们吗?

标签: java unit-testing junit mockito


【解决方案1】:

我假设您正在尝试测试您的 getNameInc(..) 方法。当您调用它时,它会在您指定的目录中查找文件,并根据找到的内容装饰您给它的名称。

为了使类可单元测试,您应该抽象对文件系统的依赖,以便在模拟中,您可以模拟您想要的任何目录内容。您的类将接受此接口的一个实例作为依赖项,并调用它以找出目录中的内容。当您在程序中真正使用该类时,您将提供此接口的实现,该实现委托给 JDK 文件系统调用。当您对该类进行单元测试时,您将提供此接口的 Mockito 模拟。

避免在 FilesystemImpl 类中放入过多的逻辑,因为您无法为它编写严格的单元测试。让它成为一个非常简单的文件系统包装器,这样所有智能的东西都在 Yourclass 中,您将为其编写大量的单元测试。

public interface Filesystem {
    boolean contains(String dirpath, String filename);
}

public class FilesystemImpl {
    boolean contains(String dirpath, String filename) {
        // Make JDK calls to determine if the specified directory has the file.
        return ...
    }
}

public class Yourmainclass {
    public static void main(String[] args) {

         Filesystem f = new FilesystemImpl();
         Yourclass worker = new Yourclass(f);
         // do something with your worker
         // etc...
    }
}

public class Yourclass {
    private Filesystem filesystem;

    public Yourclass(Filesystem filesystem) {
        this.filesystem = filesystem;
    }

    String getNameInc(String dirpath, String filename) {
       ...
       if (filesystem.contains(dirpath, filename) {
          ...
       }
    }

}

public class YourclassTest {

   @Test
   public void testShouldAppendAAWhenFileExists() {
       Filesystem filesystem = Mockito.mock(Filesystem.class);
       when(filesystem.contains("/some/mock/path", "bankAccount.pdf").thenReturn(true);
       Yourclass worker = new Yourclass(filesystem);
       String actual = worker.getNameInc("/some/mock/path", "bankAccount.pdf");
       assertEquals("bankAccountAA.pdf", actual);
   }

   @Test
   public void testShouldNotAppendWhenFileDoesNotExist {
       Filesystem filesystem = Mockito.mock(Filesystem.class);
       when(filesystem.contains("/some/mock/path", "bankAccount.pdf").thenReturn(false);
       Yourclass worker = new Yourclass(filesystem);
       String actual = worker.getNameInc("/some/mock/path", "bankAccount.pdf");
       assertequals("bankAccount.pdf", actual);
   }
}

由于测试之间有很多重复,您可能会创建一个 setup 方法并在那里做一些工作,并创建一些实例变量供测试使用:

    private static final String TEST_PATH = "/some/mock/path";
    private static final String TEST_FILENAME = "bankAccount.pdf";
    private Filesystem filesystem;
    private Yourclass worker;

    @Before
    public void setUp() {
        filesystem = Mockito.mock(Filesystem.class);
        worker = new Yourclass(filesystem);
    }

    @Test
   public void testShouldAppendAAWhenFileExists() {
       when(filesystem.contains(TEST_PATH, TEST_FILENAME).thenReturn(true);
       String actual = worker.getNameInc(TEST_PATH, TEST_FILENAME);
       assertEquals("bankAccountAA.pdf", actual);
   }

   etc...

【讨论】:

  • 不应该 FilesystemImpl 实现 Filesystem 而不是 interface 的类?
【解决方案2】:

对于您在那里描述的内容,我不会打扰 Mockito,似乎没有任何东西可以模拟(因为它很容易操作文件系统)。

我会测试... - 如果我调用 getNameInc 并且已经没有匹配的文件会发生什么 - 如果我调用 getNameInc 并且那里已经有文件 AA-YY 会发生什么 - 如果我调用 getNameInc 并且文件 ZZ 已经存在会发生什么

不过,TDD 的重点是您应该已经编写了这些测试,然后实现您的代码以使测试通过。所以你不会真的在做 TDD,因为你已经有了代码。

【讨论】:

  • 是的,我知道在代码之后执行测试没有多大意义,但因为这对我来说是新的。我正在尝试掌握 TDD
猜你喜欢
  • 2017-09-06
  • 1970-01-01
  • 2019-06-21
  • 1970-01-01
  • 1970-01-01
  • 2022-01-07
  • 1970-01-01
  • 1970-01-01
  • 2017-09-02
相关资源
最近更新 更多