gpt4 book ai didi

java - 对 Liskov 替换原则的合规性进行单元测试是一种好的做法吗?

转载 作者:行者123 更新时间:2023-12-01 01:01:25 24 4
gpt4 key购买 nike

假设一个名为 Sprinter 的类:

public class Sprinter {

protected int travelMeters;

public void run(int seconds) {
this.travelMeters = 9 * seconds;
}

public int getTravelMeters(){
return travelMeters;
}
}

还有一个 SprintGenius 类型继承 Sprinter:

class SprintGenius extends Sprinter {

public void run(int seconds) {
this.travelMeters = 10 * seconds;
}
}

逻辑上,必须创建 2 个单元测试类,每种类型一个。

Sprinter 单元测试中,我最终会得到:

@Before
public void setUp() {
Sprinter sprinter = new Sprinter();
}

public void testSprinterShouldRun90metersWithin10Seconds() {
sprinter.run(10);
assertEquals(sprinter.getTraveledMeters(),90);
}

SprintGenius 单元测试中,我最终会得到:

@Before
public void setUp() {
Sprinter sprinter = new SprintGenius();
}

public void testSprinterShouldRun100metersWithin10Seconds() {
sprinter.run(10);
assertEquals(sprinter.getTraveledMeters(),100);
}

在上面的两个测试中,我都会在 10 秒内测试行进的米数。

显然,这两个测试都是绿色的。

但是,违反里氏替换原则怎么办?

事实上,任何客户端代码都应该期望任何短跑运动员在 9 秒内跑完 10 米。

3 个解决方案(前两个解决方案已向所有团队的开发人员发出规则,并且必须承认并保留,即使不是每个人都很好地掌握 Liskov 的概念)

1) 在 Sprinter 类中,重复每个测试,但这次基于 Sprinter sprinter = new SuperGenius() 并期望 90 米。 => 什么应该失败,这正是我们想要的! => 防止违反 Liskov 原则。

2) 在SprintGenius 类中,始终基于完全相同的期望添加基于基类的每个测试的类似“克隆”。因此,如果您有 2 个不同的测试,我们最终会得到 4 个测试。 2 将 Sprinter 声明为 Sprinter 并 2 将 Sprinter 声明为 SprintGenius

3) 从不从具体类继承(我想这是你阅读这篇文章的第一 react :)),如果合适的话,更喜欢组合!这样就不会出现这个问题。

基于许多开发人员忽略 Liskov 原则并且经常试图从具体类继承而不是使用另一种更好的方法(如组合或不同的继承层次结构)这一事实,防止违反 Liskov 替换原则的最佳实践是什么?

我不想因为开发人员继承了我编写的类(没有告诉我......),将它注入(inject)到一个共享的巨大的异构 Sprinter 列表中并面对我说“你好奇怪的行为!”和数小时的调试时间...

我当然不想将我所有的具体类都声明为“final”:)

最佳答案

单元测试是关于特定模块的测试,不能也不应该用于比这更广泛的事情。遵守 Liskov 替换原则是系统范围内的一个更广泛的问题,而不是模块范围内的问题。而且,它不是要在代码中测试的东西。这是一个纯粹的设计问题,与实现无关。我不认为 LSP 可以通过自动工具强制执行。它应该在设计审查期间处理,然后在代码审查期间处理(应该检查是否符合设计)。

关于java - 对 Liskov 替换原则的合规性进行单元测试是一种好的做法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13194154/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com