单元测试的疑惑

2022-06-29 09:53:43 +08:00
 AS4694lAS4808
最近写一个新项目,其中有一个函数是根据父级 id 从数据库查出几十条数据,发到 pulsar 等下游服务返回结果,再更新回数据库,逻辑很简单,也就不到 50 行代码。



对于这块的单元测试不知道该怎么写。。因为有其他项目也在操作开发数据库,根据父级 id 可能查出来为空,这时逻辑是 ok 的。然后下游的服务也不一定一直监听消息,另外如果监听了,下游服务会产生业务逻辑更新它们的库。。所以这种情况该怎么写单元测试呢?



如果测试方法只是调用函数,检查有没有异常,好像作用不大。如果是 sql 查出有结果的父级 id 再调用函数,感觉增加了测试的变量,jenkins 执行 mvn 的时候没准会失败。而且即使成功查出数据,还会造成下游服务的数据非正常更改。。



之前单元测试写的少,都是比较好拆分的模块,最近要求测试模块详细完整了,所以有点摸不着头脑。。
2742 次点击
所在节点    Java
12 条回复
zhazi
2022-06-29 10:12:46 +08:00
测试是测试你的 [代码逻辑] 。跟数据库完全隔离的
var obj = new SomeObj() ;
when(mockDb.findByParentId(any())).thenReturn(obj);
business.logic(something);
Mockito.verify(rpc.call(),times(1));

doThing().when(mockDb.findByParentId(any());
business.logic(something);
Mockito.verify(rpc.call(),nvner());

这种测试可以保证你的 business.logic 的逻辑

至于你的 dao 层需要去断言 sql 写的是否正确 这种测试除非把业务写进 sql 里才需要去测试
var query = JpaQueryFactory.select(*).from(tableA).where(tableA.name.equals("actualField");
String expected = "select * from tableA where tableA.name = "actualField";
Assertions.assertEquals(expected,query.toString());
yinhuochong6666
2022-06-29 10:12:52 +08:00
既然他叫单元测试,还使用真实的上下游服务器数据库,这本身就是个错误
timethinker
2022-06-29 10:15:13 +08:00
这个不是单元测试吧,这个算是集成测试了,需要在独立的测试进程中对其进行测试,就好像是应用程序的真实使用者一样。

对于单元测试,如果测试的目标依赖了一个外部的组件,常用的做法是对这种外部组件进行 Mock ,比如测试目标需要一个发送消息的服务( MessagePublisher ),可以 Mock 一个消息发送服务( InMemoryMessagePublisher ),然后对测试目标进行测试,并观察 InMemoryMessagePublisher 中的结果是否符合预期,当然这只是一个很简单的例子,因为单元测试足够小,所以可以反复快速的完成测试内容。

测试是一个很复杂的概念,每个人或者组织都有不同的偏好,在我看来归根结底无非就是两个问题,那就是搞清楚我们到底在测试什么?我们期望测试将来可以起到什么帮助?
dayeye2006199
2022-06-29 10:30:04 +08:00
Don't test what you do not own.

不测试你不拥有的系统
AS4694lAS4808
2022-06-29 10:32:59 +08:00
@zhazi sql 基本都是 mybatis-plus 搞的,倒是没有验证 sql 语句本身的需求。

好像有点明白了,就是我应该把函数内部的 dao 和 mq 操作的 service bean 放到类属性,用 mockito 来生成,然后再调用方法测试吧?(现在 bean 是函数内从 ApplicationContext 获取的。。)
之前主要是想非侵入的写个测试方法,看来钻牛角尖了。。

非常感谢!
Morii
2022-06-29 10:33:18 +08:00
你这里属于集成测试了,需要 mock 依赖的的服务、中间件,然后测试流程中插桩处理异常情况
AS4694lAS4808
2022-06-29 10:33:59 +08:00
@yinhuochong6666 很有道理,之前没想明白怎么 mock ,现在想明白了。。谢谢!
AS4694lAS4808
2022-06-29 10:35:44 +08:00
@timethinker 是的,这两个问题应该是清楚了。感谢!
MiracleShadow
2022-06-29 11:58:11 +08:00
函数有点复杂的,拆一拆然后测试呢?
nothingistrue
2022-06-29 12:16:43 +08:00
单元测试不测试与它无关的东西,外部依赖一律 mock 。
AS4694lAS4808
2022-06-29 13:34:41 +08:00
@MiracleShadow 因为函数很短,就没想着改动。。思路不对。。
filwaline
2022-06-29 23:37:02 +08:00
https://enterprisecraftsmanship.com/book

个人推荐你看看这本书,全面讲解了单元测试是什么,以及怎么写好的测试。书籍要付费购买,但是非常值得。

比如,你的问题,就是需要拆分的情况 (over complicated code),应用 humble object pattern 将其拆分为 domain model 和 controller ,然后针对 domain model 写 unit test ,如果有必要就为 controller 也写一个 intergeation test

![types-of-code]( https://drek4537l1klr.cloudfront.net/khorikov/Figures/07fig05_alt.jpg)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/862839

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX