Java`final`类和嘲弄

时间:2012-10-30 13:01:51

标签: java unit-testing maven mocking mockito

我正在开发一种编程游戏,玩家可以访问抽象类并扩展它以控制机器人的行为。因为它是一个编程游戏,我试图保护我的游戏基础设施,以便玩家不会混淆游戏,而不仅仅是我给他们的课程;为此我创建了大部分课程final,但现在我无法在单元测试中模拟它们(mockito + testNG)。

所以我想知道,我该如何解决这个问题?有没有办法可以让这些类非最终用于测试,然后以某种方式在构建周期的后期自动“final - ize”它们(我正在使用maven,以防它与答案相关) 。我不想添加另一个外部库或更改我的模拟库 如果不可能,那么第二个问题:使类final真正安全吗?我看到一些库可以从字节码中删除final分类器,这让我觉得如果可以从已编译的类

中删除它,那么final可能就没用了

5 个答案:

答案 0 :(得分:9)

首先,你不能通过宣布“最终”来阻止人们搞乱你的游戏。有反射技巧和整个代码生成库,只是稍微不方便通过它。

所以,输掉决赛,然后你就可以使用jmock或者你喜欢的任何图书馆来制作嘲笑。

答案 1 :(得分:2)

您最终可以尝试应用自动重构工具,例如Jackpot 3RefactoringNG。我从未对它们进行过测试,但如果采用重构的方式,它们就能胜任你想做的事。

另一种方法是使用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设计实践)。