mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-01-09 20:00:21 +08:00
add kotlin demo for mock scope
This commit is contained in:
parent
b68ff99800
commit
0e581a7eeb
@ -7,19 +7,19 @@ package com.alibaba.demo.association;
|
||||
public class CookerService {
|
||||
|
||||
private static String hireSandwichCooker() {
|
||||
return "Sandwich-Cooker";
|
||||
return "Real-Sandwich-Cooker";
|
||||
}
|
||||
|
||||
private static String hireHamburgerCooker() {
|
||||
return "Hamburger-Cooker";
|
||||
return "Real-Hamburger-Cooker";
|
||||
}
|
||||
|
||||
private String cookSandwich() {
|
||||
return "Cooked-Sandwich";
|
||||
return "Real-Sandwich";
|
||||
}
|
||||
|
||||
private String cookHamburger() {
|
||||
return "Cooked-Hamburger";
|
||||
return "Real-Hamburger";
|
||||
}
|
||||
|
||||
public String prepareSandwich() {
|
||||
|
@ -15,7 +15,7 @@ class SellerServiceTest {
|
||||
|
||||
@Test
|
||||
void should_sell_hamburger() {
|
||||
assertEquals("Hamburger-Cooker & Cooked-Hamburger", sellerService.sellHamburger());
|
||||
assertEquals("Real-Hamburger-Cooker & Real-Hamburger", sellerService.sellHamburger());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
package com.alibaba.demo.association
|
||||
|
||||
/**
|
||||
* 目标类,此类中的一些调用将会被Mock掉
|
||||
* Target class, some invocations inside this class will be mocked
|
||||
*/
|
||||
class CookerService {
|
||||
|
||||
private fun cookSandwich(): String {
|
||||
return "Real-Sandwich"
|
||||
}
|
||||
|
||||
private fun cookHamburger(): String {
|
||||
return "Real-Hamburger"
|
||||
}
|
||||
|
||||
fun prepareSandwich(): String {
|
||||
return hireSandwichCooker() + " & " + cookSandwich()
|
||||
}
|
||||
|
||||
fun prepareHamburger(): String {
|
||||
return hireHamburgerCooker() + " & " + cookHamburger()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun hireSandwichCooker(): String {
|
||||
return "Real-Sandwich-Cooker"
|
||||
}
|
||||
|
||||
private fun hireHamburgerCooker(): String {
|
||||
return "Real-Hamburger-Cooker"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.alibaba.demo.association
|
||||
|
||||
/**
|
||||
* 被测类,会访问`CookerService`里的方法
|
||||
* Class to be tested, which will access methods in TargetService class
|
||||
*/
|
||||
class SellerService {
|
||||
|
||||
private val cookerService = CookerService()
|
||||
|
||||
fun sellSandwich(): String {
|
||||
return cookerService.prepareSandwich()
|
||||
}
|
||||
|
||||
fun sellHamburger(): String {
|
||||
return cookerService.prepareHamburger()
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.alibaba.demo.association
|
||||
|
||||
import com.alibaba.testable.core.annotation.MockMethod
|
||||
import com.alibaba.testable.core.model.MockScope
|
||||
|
||||
internal class CookerServiceMock {
|
||||
|
||||
@MockMethod(targetClass = CookerService::class)
|
||||
private fun cookSandwich(): String {
|
||||
return "Faked-Sandwich"
|
||||
}
|
||||
|
||||
@MockMethod(targetClass = CookerService::class, scope = MockScope.ASSOCIATED)
|
||||
private fun cookHamburger(): String {
|
||||
return "Faked-Hamburger"
|
||||
}
|
||||
|
||||
@MockMethod(targetClass = CookerService::class)
|
||||
fun hireSandwichCooker(): String {
|
||||
return "Fake-Sandwich-Cooker"
|
||||
}
|
||||
|
||||
@MockMethod(targetClass = CookerService::class, scope = MockScope.ASSOCIATED)
|
||||
fun hireHamburgerCooker(): String {
|
||||
return "Fake-Hamburger-Cooker"
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.alibaba.demo.association
|
||||
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class SellerServiceTest {
|
||||
|
||||
private val sellerService = SellerService()
|
||||
|
||||
@Test
|
||||
fun should_sell_sandwich() {
|
||||
Assertions.assertEquals("Fake-Sandwich-Cooker & Faked-Sandwich", sellerService.sellSandwich())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun should_sell_hamburger() {
|
||||
Assertions.assertEquals("Real-Hamburger-Cooker & Real-Hamburger", sellerService.sellHamburger())
|
||||
}
|
||||
}
|
@ -6,11 +6,15 @@ Mock的生效范围
|
||||
- `MockScope.GLOBAL`:该Mock方法将全局生效
|
||||
- `MockScope.ASSOCIATED`:该Mock方法仅对Mock容器关联测试类中的测试用例生效
|
||||
|
||||
举例来说,`AaaService`和`BbbService`是两个需要被测试的类,在`BbbService`的代码里有个`recordTicket()`调用依赖外部系统。因此在进行单元测试时,开发者在`BbbService`关联的Mock容器里使用`@MockMethod`注解定义了这个调用的替代方法。此时,若该Mock方法的`scope`值为`MockScope.GLOBAL`,则不论是在`AaaServiceTest`测试类还是在`BbbServiceTest`测试类的测试用例,只要直接或间接的执行到这行调用,都会被置换为调用Mock方法。若该Mock方法的`scope`值为`MockScope.ASSOCIATED`,则Mock只对`BbbServiceTest`类中的测试用例生效,而`AaaServiceTest`类中的测试用例在运行过程中执行到了`BbbService`类的相关代码,将会执行`recordTicket()`的原本调用。
|
||||
|
||||
对于常规项目而言,单元测试里需要被Mock的调用都是由于其中包含了不需要或不便于测试的逻辑,譬如“依赖外部系统”、“包含随机结果”、“执行非常耗时”等等,这类调用在整个单元测试的生命周期里都应该被Mock方法置换,不论调用的发起者是谁。因此`TestableMock`默认所有Mock方法都是全局生效的,即`scope`默认值为`MockScope.GLOBAL`。
|
||||
|
||||
在一些大型项目中,会有“下层模块编写单元测试,上层模块编写端到端集成测试,两者混合在一起运行”的情况,这时候大部分Mock方法都应该使用`MockScope.ASSOCIATED`作为生效范围。针对这种情况,`TestableMock`支持通过`mockScope`运行参数来修改默认的Mock方法生效范围,详见[全局运行参数](zh-cn/doc/javaagent-args.md)文档。
|
||||
> 举例来说,`CookerService`和`SellerService`是两个需要被测试的类,假设`CookerService`的代码里的`hireXxx()`和`cookXxx()`方法都需要依赖外部系统。因此在进行单元测试时,开发者在`CookerService`关联的Mock容器里使用`@MockMethod`注解定义了这些调用的替代方法。
|
||||
>
|
||||
> 此时,若该Mock方法的`scope`值为`MockScope.GLOBAL`,则不论是在`SellerServiceTest`测试类还是在`CookerServiceTest`测试类的测试用例,只要直接或间接的执行到这行调用,都会被置换为调用Mock方法。若该Mock方法的`scope`值为`MockScope.ASSOCIATED`,则Mock只对`CookerServiceTest`类中的测试用例生效,而`SellerServiceTest`类中的测试用例在运行过程中执行到了`CookerService`类的相关代码,将会执行原本的调用。
|
||||
>
|
||||
> 参见Java和Kotlin示例中`SellerServiceTest`测试类的用例。
|
||||
|
||||
在一些大型项目中,会有“下层模块编写单元测试,上层模块编写端到端集成测试,两者混合在一起运行”的情况,这时候大部分Mock方法都应该使用`MockScope.ASSOCIATED`作为生效范围。针对这种情况,`TestableMock`支持通过`mock.scope.default`运行参数来修改默认的Mock方法生效范围,详见[全局运行参数](zh-cn/doc/javaagent-args.md)文档。
|
||||
|
||||
> 特别说明。若要Mock静态块里的调用,Mock方法的`scope`必须为`MockScope.GLOBAL`,因为静态块中的代码在程序初始化时就会执行,不属于任何测试用例。典型场景是在使用JNI开发的项目中Mock系统库的加载方法。
|
||||
> ```java
|
||||
|
Loading…
Reference in New Issue
Block a user