正确的状态是消费者消费锤子、刀、螺丝刀,c=(锤子,刀,螺丝刀),生产者生产锤子,刀,螺丝刀,p=(锤子,刀,螺丝刀)。有四种回归场景:
- c=(锤子,刀,螺丝刀,剑), p=(锤子,刀,螺丝刀)
- c=(锤子,刀,螺丝刀), p=(锤子,刀,螺丝刀,剑)
- c=(锤子,刀,螺丝刀), p=(锤子,刀)
- c=(锤子,刀), p=(锤子,刀,螺丝刀)
1 和 3 以非常温和的方式违约。在第一种情况下,客户声明了一种新的类型,但生产者不支持。在第三种情况下,生产者停止支持一种类型。场景的严重性当然可能是谨慎的,因为我认为软回归可能存在于关键业务流程中的某个服务中。但是,如果它很关键,那么就有很大的动机用专门的测试用例来覆盖它。第 2 和第 4 种情况更为严重,在这两种情况下,消费者可能最终都会出错,例如可能无法反序列化数据。
每种类型都有一个测试用例应该检测场景 3 和 4。在第一个场景中,它可能会触发开发人员创建一个额外的测试用例,该测试用例将在生产者站点上失败。但是,测试用例对第二种情况无能为力。因此,尽管成本相对较高,但这种策略并没有为我们提供完整的测试覆盖率。
拥有一个包含所有有效类型的正则表达式的测试用例(即锤子|刀|螺丝刀)应该是消费者开发人员在第 1 和第 4 场景中重新设计测试用例的强大触发因素。一旦正则表达式适应新的消费者能力,它就可以检测到概率 p=1/3 的场景 4(即,如果生产者选择螺丝刀作为样本值,则测试将失败)。即使没有正则表达式调整,它也会检测 p=1/3 的第三种情况。这种策略对第一种和第二种情况是无能为力的。
然而,在正则表达式之上,我们可以做更多的事情。即,我们可以用随机数据设计生产者测试用例。假设所讨论的类型定义如下:
enum Tool {hammer,knife,screwdriver}
我们可以使用以下方式渲染测试数据:
responseBody = Arranger.some(Tool.class);
这段代码使用test-arranger,但还有其他库也可以这样做。它选择一个有效的枚举值。每次都可以是不同的。它有什么变化?现在我们可以检测到第 2 种情况,并在 regex 调整后检测第 4 种情况。所以它涵盖了最严重的场景。还有一个缺点需要考虑。生产者测试是不确定的,取决于绘制的值,它可以成功或失败,这被认为是一种反模式。当一些测试有时会失败,尽管测试的代码是正确的,人们开始忽略测试的结果。请注意带有随机数据的生产者测试用例并非如此,事实上恰恰相反。尽管测试的代码不正确,它有时也会成功。它仍然远非完美,但这是一个有趣的权衡,因为它是第一个设法解决非常严重的第二种情况的策略。
我的建议是在客户端使用带有正则表达式支持的随机数据的生产者测试用例。尽管如此,没有完美的解决方案,您应该始终考虑什么对您的服务很重要。具体来说,如果消费者可以安全地忽略未知值,那么推荐的方法可能并不完美。