如何测试(模拟)使用外部API的对象(Jama Software)

时间:2016-06-21 14:23:17

标签: java unit-testing junit mocking mockito

我在尝试测试Class时遇到了问题,它使用外部API -

  

Jama Software

。 假设有一个ClassA。它有2个方法,我想用JUnit测试。 两种方法都以ClassB为参数。

ClassB属于另一个API。我可以看到它的方法,但实现细节不可用。(compiled code)。问题是:如何模拟这些类以使TestClass被隔离?我知道在Mockito中有hardcode个回复的选项。有没有 更好/更清洁 的方法,所以我不需要手动配置模拟对象?对于有关该主题的任何建议,我将不胜感激。

1 个答案:

答案 0 :(得分:1)

A good read about mocking来自另一个答案。

将mock与其方法一起使用的目的是将其与依赖关系隔离开来。模拟参数可能看似肮脏或不合适,但它旨在允许您测试模拟类的期望。在这种情况下,您假设无论您的服务ClassB是什么,都按预期工作(如果您也期望例外,则不工作)。在这种情况下,我们正在测试单个单元 ClassA并假设ClassB是正确的。

我会继续做一个更具体的例子,类似于上面的服务员/厨师例子。

假设你的ClassA是一个CookingPot而你的ClassB是一个Pantry。每当你与Pantry交互到getPasta时,它都会向你发送Pasta。如果没有Pasta,则返回null。

Pantry是一个花哨的Pantry。它有一个存储其内容的表,所以你不知道它是否有意大利面。这在现实世界中是“复杂的”,但这不是我们的Pantry。我们不知道它是如何工作的,只是它要么返回Pasta,要么它没有。我们不知道逻辑,也不知道我们必须。我们知道它的作用,所以如果我们想确保我们可以在我们的锅中加入意大利面,我们就可以使用一个模拟的Pantry,它的行为方式相同,而不会让花哨的铃声真正的哨声。

Pantry还有许多其他方法,例如允许您将剩余的意大利面添加回货架。你不知道聪明的Pantry如何将意大利面放回去,但是你不需要对它进行建模,因为无论如何,Mockito都可以使用void函数。

如果ClassB要改变,这些测试可能仍然会通过,但是你会在集成测试中发现这个问题然后说“嗯,我的班级仍然可以工作,但是新的Pantry会有所作为,所以我需要重做班级,并重新连接测试。“

CookingPot {
    void addPasta(Pantry pantry) {
        Pasta p = pantry.getPasta();
        System.out.println("Added " + p.toString() + " to the pot!"); 
        //fancy actions that use up some of the Pasta
        pantry.add(p); //return the pasta
    }
}

Pantry {
    Pasta getPasta(); //we have no idea what this does in actuality
}


@Test(expected = NullPointerException.class)
public void testAddPastaButNoPastaLeft() {
    Pantry mockPantry = mock(Pantry.class);

    CookingPot cookingPot = new CookingPot();
    cookingPot.addPasta(mockPantry);
    //we should probably have checked if there was pasta before 
    //attempting to add imaginary pasta
}

@Test
public void testAddPasta() {
    Pantry mockPantry = mock(Pantry.class);
    when(mockPantry.getBaz()).thenReturn(new Pasta());

    CookingPot cookingPot = new CookingPot();
    cookingPot.addPasta(mockPantry);
}