问题

我是开发新手,特别是单元测试。我想我的要求很简单,但我很想知道其他人的想法。

假设我有两个类似的 -

public class First {

    Second second ;

    public First(){
        second = new Second();
    }

    public String doSecond(){
        return second.doSecond();
    }
}

class Second {

    public String doSecond(){
        return "Do Something";
    }
}

假设我正在为testFirst.doSecond()方法编写单元测试。但是,假设,我想MockSecond.doSecond()class如此。我正在使用Mockito这样做。

public void testFirst(){
    Second sec = mock(Second.class);
    when(sec.doSecond()).thenReturn("Stubbed Second");

    First first = new First();
    assertEquals("Stubbed Second", first.doSecond());
}

我看到模拟没有生效,断言失败了。有没有办法模拟我想测试的类的成员变量。 ?


#1 热门回答(64 赞)

你需要提供一种访问成员变量的方法,以便传入模拟(最常见的方法是setter方法或带参数的构造函数)。

如果你的代码没有提供这样做的方法,那么TDD(测试驱动开发)就会错误地考虑它。


#2 热门回答(48 赞)

如果你无法更改代码,则无法执行此操作。但我喜欢依赖注入,Mockito支持它:

public class First {    
    @Resource
    Second second;

    public First() {
        second = new Second();
    }

    public String doSecond() {
        return second.doSecond();
    }
}

你的考试:

@RunWith(MockitoJUnitRunner.class)
public class YourTest {
   @Mock
   Second second;

   @InjectMocks
   First first = new First();

   public void testFirst(){
      when(second.doSecond()).thenReturn("Stubbed Second");
      assertEquals("Stubbed Second", first.doSecond());
   }
}

这非常好,很容易。


#3 热门回答(31 赞)

如果你仔细查看你的代码,你会发现你的测试中的second属性仍然是Second的实例,而不是模拟(你没有在你的代码中传递模拟到first)。

最简单的方法是创建一个forsecondinFirstclass的setter并明确地将它传递给mock。

喜欢这个:

public class First {

Second second ;

public First(){
    second = new Second();
}

public String doSecond(){
    return second.doSecond();
}

    public void setSecond(Second second) {
    this.second = second;
    }


}

class Second {

public String doSecond(){
    return "Do Something";
}
}

....

public void testFirst(){
Second sec = mock(Second.class);
when(sec.doSecond()).thenReturn("Stubbed Second");


First first = new First();
first.setSecond(sec)
assertEquals("Stubbed Second", first.doSecond());
}

另一种方法是传递aSecond实例asFirst的构造函数参数。

如果你无法修改代码,我认为唯一的选择是使用反射:

public void testFirst(){
    Second sec = mock(Second.class);
    when(sec.doSecond()).thenReturn("Stubbed Second");


    First first = new First();
    Field privateField = PrivateObject.class.
        getDeclaredField("second");

    privateField.setAccessible(true);

    privateField.set(first, sec);

    assertEquals("Stubbed Second", first.doSecond());
}

但你可能会这样做,因为很少对你无法控制的代码进行测试(尽管人们可以想象你必须测试外部库的情况,因为它的作者没有:))


原文链接