Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java`final`类和模拟_Java_Unit Testing_Maven_Mocking_Mockito - Fatal编程技术网

Java`final`类和模拟

Java`final`类和模拟,java,unit-testing,maven,mocking,mockito,Java,Unit Testing,Maven,Mocking,Mockito,我正在开发一个编程游戏,玩家可以访问一个抽象类并扩展它来控制机器人的行为。因为这是一个编程游戏,我试图保护我的游戏基础设施,这样玩家就不会在游戏中捣乱,而不仅仅是我给他们的课程;为此,我将大部分类设置为final,但现在我无法在单元测试(mockito+testNG)中模拟它们 所以我想知道,我该如何解决这个问题?有没有一种方法可以让类保持非final的状态以供测试,然后在构建周期的后期自动地“final-ize”它们(我正在使用maven,以防它与答案相关)。我不想添加其他外部库或更改模拟库。

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

所以我想知道,我该如何解决这个问题?有没有一种方法可以让类保持非final的状态以供测试,然后在构建周期的后期自动地“
final
-ize”它们(我正在使用maven,以防它与答案相关)。我不想添加其他外部库或更改模拟库。

如果不可能,那么第二个问题:是否使类
final
真正安全?
我看到一些库可以从字节码中删除
final
分类器,这让我认为如果可以先从已编译的类中删除它,那么
final
可能是无用的,你不能通过宣布事情“最终”来阻止人们干扰你的游戏。有一些反射技巧和完整的代码生成库,这使得克服这个问题有点不方便


因此,如果没有期末考试,那么您可以使用jmock或任何您喜欢的库来进行模拟。

IMO,类被标记为final,以使其对象不可变。如果要控制类的行为,可以将类中的方法标记为private,以便它们不能被重写。如果您让它们处于保护状态,那么有人可以扩展您的类,重写这些受保护的方法,并将扩展类的实例传递给希望您的类对象作为参数的API,从而导致修改的行为。因此,您可以将不想公开的方法标记为私有


您只保留受保护/公共方法的扩展点,这些方法可以由使用这些类的客户端为自定义行为重写。

您始终可以使用委派而不是继承

public interface Foo {
    // ...
}

public final class FooImpl implements Foo {
    // ...
}

public class MockFooImpl implements Foo {
    private FooImpl delegate;
    // ...
}

然而,在API中使用抽象类是个坏主意。界面会更好。

您最终可以尝试应用自动化重构工具,如或。我从未对它们进行过测试,但如果采用重构的方式,它们完全可以做你想做的事情


另一种方法是使用Powermock,它允许模拟final和statics(即使很难,我也不喜欢模拟statics,因为它表明您的设计中存在错误)。

使大多数类成为final是一种很好的做法,因为它们通常不是为通过子类化进行扩展而设计的。我所知道的所有关于API设计的书籍都建议这样做(“有效的Java”、“实用的API设计”、“针对C++的API设计”)。这是有益的,有几个原因,包括表达API设计者的意图、API的安全发展以及防止死代码(例如,好的IDE将检测
final
方法何时不使用其参数之一,或者从不抛出
throws
子句中列出的选中异常-这对于非final方法是不可能的)


至于模拟上述类,您只需要使用适当的模拟工具,例如(我开发该工具正是因为我想在不牺牲某些OO/API设计实践的情况下编写单元测试).

我建议使用接口而不是类。并且使用DI。一旦代码在机器上运行,就不可能防止人们弄乱代码。这在某种程度上适用于所有程序,但java程序更是如此,因为java类非常容易反编译。无论你做什么,他们都可以简单地反编译你的代码编码、修改和重新编译它,从而改变它的行为。包括
final
是Java编程语言最糟糕的设计决策之一。我敢让任何人向我展示一个有效用法的好例子,它实际上增加了价值,我很乐意用大约100个例子来反驳它,在这些例子中,它只会增加挫败感、缺乏灵活性ty和代码重复。如果Oracle干脆放弃
final
,我会是一个快乐的开发者。关于你的第二个问题:使用
final
是一个OO设计问题,是一种帮助静态分析工具帮助我们编写更好代码的方法,而不是让代码“安全”的方法。是否可以在运行时修改
final
或字节码的任何其他内容通常都不相关;安全的环境需要一个沙盒,Java通过
SecurityManager
支持沙盒,但这通常只用于小程序和托管Java EE容器中。好吧,我当时就是这么想的:
final
与其说是一个安全实施者,不如说是一个设计师的意图(即“这个类不应该被扩展”,而不是“这个类不能被扩展”).这是我最初的想法,但后来我开始阅读,我一直认为“安全性”是其原因之一。我想我读到的源代码不好如果你可以在你用SecurityManager控制的JVM中运行代码,那么它就有一些安全性。但是如果你能做到这一点,那么,你为什么需要它?正如其他答案中指出的,你不需要它因为存在模拟工具,它们与
final
方法或类没有问题。因为继承不是由我完成的,而是由模拟库完成的,所以这不是一个选项