Unit testing (java): Will I have to write public methods to expose data to unit tests?
我已经看过了,但它并没有真正的答案。有时你需要测试一个类的某些行为,但是为了你真正断言你有预期的行为,你需要检查它的一些私有数据。
一个例子:我正在创建一个类,它将返回从文件中读取的随机单词。所以我设计了一个这样的类:
1 2 3 4 5 6 7 8 9 10 11 | public class WordsDatabase { private List<String> wordsList = new ArrayList<String>(); public WordsDatabase() { fillWordsListFromFile(); } private void fillWordsListFromFile() {...} public String getRandomWord() {...} } |
我不想暴露wordsList,但是现在如果getRandomWord()真的从我的字典文本文件中获取一个随机单词,我应该如何进行单元测试?
我可以测试的是它是否返回一个单词,但我不知道该单词是否是从文件中随机选取的。
为了测试我可以执行Chi Square测试以进行均匀分布,但是至少我必须知道wordsList.size(),以某种方式暴露它。
也许我只是愿意进行太深入的测试......
编辑:
谢谢你的答案,得到了提示。当我的课很难测试时,可能是因为它的设计有问题。
"如果getRandomWord()真的从我的字典文本文件中获取一个随机单词,我应该如何进行单元测试?"
这听起来像是模拟和依赖注入的完美用例。
如果您使用像spring这样的框架,那么它就是为依赖注入而设计的。另一个答案有一些关于使用弹簧来解决这个问题的好指示。
您应该只测试公共方法,以确定您的类是否按照您的喜好工作。
测试对象的内部状态不是一个好习惯,因为对象的内部表示可以改变,但方法行为可以保持不变。
因此,您无需更改变量/方法的可见性以对单元进行单元测试,并且您不应使用Reflection进行测试(有时它会用作解决此类问题的提示)。
注意:如果你需要知道wordsList的大小。您需要检查wordsList的填充方式。从你的代码看来它是从一个文件填充。因此,您要定义要在测试中使用的文件。知道了这个文件的内容,你不需要检查wordsList大小的内部值。
改变您的设计可以让您更轻松地测试您的课程。例如,您可以向
1 2 3 4 5 6 7 8 9 10 11 | public class WordsDatabase { private List<String> wordsList = new ArrayList<String>(); public WordsDatabase(WordService wordService) { wordsList.addAll(wordService.getWords()); } public String getRandomWord() { // Interact with wordsList or wordService directly. } } |
示例服务接口:
1 2 3 | public interface WordService { List<String> getWords(); } |
现在,在您的测试中,您可以模拟
如果你控制你的类的依赖性,这种问题(很大程度上)就会消失。查看依赖注入的示例以获取更多信息。
除非你真的没有选择,否则你绝对不应该使用反射进行JUnit测试。如果要执行涉及私有变量的测试,则应使用注入或自动装配。
考虑使用这些类型的注释:
在您的情况下,对于您的列表,@ Inject或@Autowire是最适合注入变量的注释。请记住,您需要定义应用程序上下文。使用Spring或仅使用J2EE或支持CDI的任何其他优秀平台。
更重要的是,如果你出于某种原因拥有私有方法,那么请保持这种方式。我认为通常将方法公开只是为了满足单元测试是一个坏主意。