认识单元测试中的打桩



       什么是桩

       桩,或称桩代码,是指用来代替关联代码或者未实现代码的代码。如果函数BB1来代替,那么,B称为原函数,B1称为桩函数。打桩就是编写或生成桩代码。

       打桩的目的

       打桩的目的主要有:隔离、补齐、控制。

       隔离是指将测试任务从产品项目中分离出来,使之能够独立编译、链接,并独立运行。隔离的基本方法就是打桩,将测试任务之外的,并且与测试任务相关的代码,用桩来代替,从而实现分离测试任务。例如函数A调用了函数B,函数B又调用了函数CD,如果函数B用桩来代替,函数A就可以完全割断与函数CD的关系。

       补齐是指用桩来代替未实现的代码,例如,函数A调用了函数B,而函数B由其他程序员编写,且未实现,那么,可以用桩来代替函数B,使函数A能够运行并测试。补齐在并行开发中很常用。

       控制是指在测试时,人为设定相关代码的行为,使之符合测试需求。例如:

externint B();

 

int A()

{

      int ret = B();

      if(ret == 0)

           ;//do something

    elseif(ret == 1)

           ;//do something

    else

           ;//do something

 

      return ret;

}

 

        如果函数B返回随机数,或者返回网络状态,或者返回环境温度,等等,则当调用其实际代码时,函数A很难测试,这时可以用桩函数B1来代替B,使其返回测试所需要的数据。

        一个桩函数,可能既具有控制功能,又具有隔离或补齐功能。

        编写桩

        一般来说,桩函数要具有与原函数完全一致的原形,仅仅是实现不同,这样测试代码才能正确链接到桩函数。

        用于实现隔离和补齐的桩函数一般比较简单,只需把原函数的声明拷过来,加一个空的实现,能通过编译链接就行了。

       比较复杂的是实现控制功能的桩函数,要根据测试的需要,输出合适的数据,下面是一个示例:

//获取环境温度。温度由出参pTemperature输出,返回值表示获取温度是否成功,如果成功,则返回1,否则返回0

int GetTemperature(int* pTemperature)

{

      if(caseNameIs("failed"))

           return 0;

 

      if(caseNameIs("ok-23"))

      {

           *pTemperature = 23;

           return 1;

      }

 

      if(caseNameIs("ok-25"))

      {

           *pTemperature = 25;

           return 1;

      }

 

      if(caseNameIs("ok-28"))

      {

           *pTemperature = 28;

           return 1;

      }

 

      return 0;

}

 

       其中,caseNameIs()是由测试工具提供的API,用于判断用例的名称。代码根据用例名称来决定输出数据。


原文地址:http://blog.youkuaiyun.com/wangwencong/article/details/8189778

### Java 单元测试中使用 Mock 框架进行异常打桩的方法 在 Java 单元测试中,当希望模拟某个方法抛出特定类型的异常时,可以通过 Mock 框架来实现这一目标。以下是具体的操作方式。 #### 使用 Mockito 进行异常打桩 Mockito 是一个广泛使用的 Java 测试框架,允许开发者轻松创建配置对象的模拟实例。对于需要验证某段代码能否正确处理异常的情况,可以利用 `doThrow()` 或者 `when()` 来设置期望发生的异常行为[^4]。 ```java import static org.mockito.Mockito.*; // 创建服务接口ServiceInterface的服务端mock对象 ServiceInterface service = mock(ServiceInterface.class); // 配置该服务中的processOrder()方法,在调用时总是抛出IllegalArgumentException doThrow(new IllegalArgumentException()).when(service).processOrder(any()); ``` 这段代码展示了如何让 `service.processOrder` 方法每次被调用时都抛出 `IllegalArgumentException` 异常。这里选择了 `doThrow()` 而不是直接作用于返回值上的 `when()`,是因为后者仅适用于那些确实会返回结果的方法;而前者则可用于任何情况下的异常设定,即使原方法声明为空操作(`void`)也无妨。 如果要使同一个方法的不同参数组合触发不同种类的异常,则可通过链式调用来完成: ```java doThrow(new RuntimeException()) .doThrow(new NullPointerException()) .when(mockedObject) .someMethod(ArgumentMatchers.anyString(), ArgumentMatchers.eq("specificValue")); ``` 上述片段表示第一次传入 `"specificValue"` 参数时将引发运行时异常 (`RuntimeException`),第二次则是空指针异常 (`NullPointerException`)。 #### 结合 JUnit 编写完整的单元测试案例 为了确保应用程序能够妥善应对各种可能遇到的错误状况,通常会在集成环境中加入相应的断言语句以确认预期的行为是否发生。下面给出一段结合了 JUnit 断言机制的例子,用于检验业务逻辑层面对异常的有效捕捉与响应能力[^1]。 ```java @Test(expected = IllegalArgumentException.class) public void testProcessOrderThrowsExceptionOnInvalidInput(){ // Arrange (setup): Prepare mocks and set up expected behavior. ServiceInterface service = mock(ServiceInterface.class); doThrow(IllegalArgumentException.class).when(service).processOrder(any()); OrderProcessor processorUnderTest = new OrderProcessor(service); // Act & Assert: Perform action under test while expecting an exception to be thrown. processorUnderTest.matchMatchingOrders(buyOrder, sellOrder); } ``` 在这个例子中,通过指定 `@Test` 注解内的 `expected` 属性告知 JUnit 当前测试函数应该期待捕获到一次非法参数异常的发生。一旦此条件未满足——即程序正常结束或抛出了不同于预设类型的其它异常——那么整个测试就会失败并报告相应信息给开发人员知晓。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值