美文网首页
测试替身(Test Double)

测试替身(Test Double)

作者: 杰哥长得帅 | 来源:发表于2018-12-01 16:07 被阅读34次

Stub(桩)

代码中不包含逻辑,作为替身只返回固定数据:

public class LogStub implement Logger {
    public String getLevel() {
        return 'DEBUG';
    }
}

Fake(伪装者)

Fake 是更加接近于生产行为的替身,如 h2database

Spy(间谍)

对于没有返回值的方法:

public class EmailSender {
    public void send(User user) {
        // 发邮件给用户...
    }
}

public class UserService { 
    private EmailSender emailSender;
    public UserService(EmailSender emailSender) {
        this.emailSender = emailSender;
    }
    public void register(User user) {
        // 注册逻辑...
        emailSender.send(user);
    }
}

在用户注册之后需要给用户发邮件,虽然发邮件不是我们关注的点,但我们仍然关心是否被成功调用,邮件的 send() 没有返回值,此时需要放出小间谍来帮助我们来完成测试:

class EmailSenderSpy extends EmailSender {
    private Boolean called = false;
    public boolean getCalled() {
        return this.called;
    }
    @Override
    public void sender(User user) {
        this.called = true;
    }
}

// 测试部分
@Test
public void should_called_send_email_to_user() {
    EmailSenderSpy spy = new EmailSenderSpy();
    UserService userService = new UserService(spy);
    User user = new User(...);
    assertEquals(false, spy.getCalled());
    userService.register(user);
    assertEquals(true, spy.getCalled());
}

Mock(模仿)

根据特定条件,返回特定的值,以验证代码的执行结果是否正确

Mock 与 Spy 的区别

当我们对 @Mock 的类,如

@Mock 
private OrderDao dao;

进行模拟方法时,会像下面这样去做:

when(dao.getOrder()).thenReturn("returened by mock "); 

但如果想对 @Spy 的类

@Spy 
private PriceService ps;

进行模拟方法时,需要像下面一样去做:

doReturn("twotwo").when(ps).getPriceTwo();

原因:
使用 @Mock 生成的类,所有方法都是模拟的,而且返回值都是 NULL
使用 @Spy 生成的类,所有方法都是真实方法,返回值都是和真实方法一样的
所以,你用 when 去设置模拟返回值时,它里面的方法会先执行一次
使用 doReturn 去设置的话,就不会产生上面的问题,因为有 when 来进行控制要模拟的方法,所以不会执行原来的方法

覆盖率上的区别

使用 @mock 模拟私有方法测试代码如下:

@RunWith(PowerMockRunner.class)
@PrepareForTest({Calculator.class})
public class CalculatorTest {
    @Test
    public void testSumXX() throws Exception {
        Calculator cal = PowerMockito.mock(Calculator.class);
        PowerMockito.when(cal,"sumXX",anyInt(),anyInt()).thenReturn(2);
        //指明callSumXX调用真实的方法
        PowerMockito.when(cal.callSumXX(anyInt(),anyInt())).thenCallRealMethod();
        assertEquals(2, cal.callSumXX(1, 2));
    }
}

因为 @mock 出来的对象可能已经发生了变化,调用的方法都不是真实的,@mock 出来的 Calculator 对应已经不是原来的 Calculator,在进行覆盖率统计时统计出来的 Calculator 类覆盖率为 0.00%

使用 @spy 模拟私有方法测试代码如下:

@RunWith(PowerMockRunner.class)
@PrepareForTest({Calculator.class})
public class CalculatorTest {
    @Test
    public void testSumXX() throws Exception {
        Calculator cal = PowerMockito.spy(new Calculator());
        PowerMockito.doReturn(2).when(cal,"sumXX",anyInt(),anyInt());
        assertEquals(2, cal.callSumXX(1, 2));
    }
}

因为 @spy 使用的真实的 Calculator 对象实例,调用的都是真实的方法,所以通过这种方式进行测试,在进行覆盖率统计时统计出来的 Calculator 类覆盖率为 50%

综上,通过 spy 的方式既能隔离环境依赖又能统计出覆盖率

相关文章

  • 测试替身(Test Double)

    Stub(桩) 代码中不包含逻辑,作为替身只返回固定数据: Fake(伪装者) Fake 是更加接近于生产行为的替...

  • 测试替身Test double

    自动化测试的一个关键是在运行时用一个模拟对象来代替系统中的一部分。这样,应用程序中被测试的那部分与系统其他部分之间...

  • Spring中集成的测试框架

    单元测试基本概念 SUT:被测系统 Test Double:测试替身,具体有Dummy Object,Test S...

  • 测试替身

    测试替身(Test Double)是为了达到测试目的并且减少被测试对象的依赖,在依赖接口编程的程序中使用Test ...

  • Go项目的测试代码3(测试替身Test Double)

    上一篇文章介绍了项目中测试代码的写法。Go项目的测试代码2(项目运用) 这里简单的共享一下测试替身。 当我们写测试...

  • Test Double总结

    Test Double 第一次了解Test Double是在Martin Fowler的文章Test Double...

  • RSpec, Test Double, Mock, and S

    Rspec是ruby的测试框架之一。 Mock和stub都属于Test double,用于测试时,模拟特定的方法或...

  • 模拟 (mock) 对象

    模拟 (mock) 对象: double可以理解为置换,它是所有模拟测试对象的统称,我们也可以称它为替身。一般来说...

  • 《Effective Unit Testing》 读书笔记 5

     在上篇读书笔记中介绍了四种测试替身,分别是stub, fake object, test spy, mock o...

  • 此处为标题?

    测试test测试test测试test测试test测试test测试test测试test测试test测试test测试t...

网友评论

      本文标题:测试替身(Test Double)

      本文链接:https://www.haomeiwen.com/subject/imhrcqtx.html