我正在开发一种编程游戏,玩家可以访问抽象类并扩展它以控制机器人的行为。因为它是一个编程游戏,我试图保护我的游戏基础设施,以便玩家不会混淆游戏,而不仅仅是我给他们的课程;为此我创建了大部分课程final
,但现在我无法在单元测试中模拟它们(mockito + testNG)。
所以我想知道,我该如何解决这个问题?有没有办法可以让这些类非最终用于测试,然后以某种方式在构建周期的后期自动“final
- ize”它们(我正在使用maven,以防它与答案相关) 。我不想添加另一个外部库或更改我的模拟库
如果不可能,那么第二个问题:使类final
真正安全吗?我看到一些库可以从字节码中删除final
分类器,这让我觉得如果可以从已编译的类
final
可能就没用了
答案 0 :(得分:9)
首先,你不能通过宣布“最终”来阻止人们搞乱你的游戏。有反射技巧和整个代码生成库,只是稍微不方便通过它。
所以,输掉决赛,然后你就可以使用jmock或者你喜欢的任何图书馆来制作嘲笑。
答案 1 :(得分:2)
您最终可以尝试应用自动重构工具,例如Jackpot 3或RefactoringNG。我从未对它们进行过测试,但如果采用重构的方式,它们就能胜任你想做的事。
另一种方法是使用Powermock,允许模拟决赛和静态(即使很难我也不喜欢嘲弄静态,因为它表明你的设计有问题)。
答案 2 :(得分:1)
您始终可以使用委派而不是继承。
public interface Foo {
// ...
}
public final class FooImpl implements Foo {
// ...
}
public class MockFooImpl implements Foo {
private FooImpl delegate;
// ...
}
但是,在API中使用抽象类是个坏主意。界面会更好。
答案 3 :(得分:0)
IMO,类被标记为final以使其对象不可变。如果要控制类的行为,请将类中的方法标记为私有,以便不能覆盖它们。如果你保护它们,那么有人可以扩展你的类,覆盖这些受保护的方法,并将扩展类的实例传递给你希望你的类对象作为参数的API,从而引发修改后的行为。因此,您可以将不希望公开的方法标记为私有。
您只保留使用这些类的客户端可以覆盖自定义行为的受保护/公共方法的扩展点。
答案 4 :(得分:0)
创建大多数类final
是很好的做法,因为它们通常不是为子类化扩展而设计的。所有关于API设计的书籍我都知道建议这样做(“Effective Java”,“Practical API Design”,“API Design for C ++”)。这有几个原因,包括表达API设计者的意图,API的安全演变以及防止死代码(例如,一个好的IDE将检测final
方法何时不使用它的一个参数,或者从不抛出throws
子句中列出的已检查异常 - 这对于非最终方法是不可能的。)
至于模拟所说的类,你只需要使用一个适当的模拟工具,例如JMockit(我开发的正是因为我想编写单元测试而不牺牲某些OO / API设计实践)。