JUnit - 如何对读取目录中的文件并使用外部库的方法进行单元测试
JUnit - How to unit test method that reads files in a directory and uses external libraries
我在 NetBeans 插件中使用了这个方法:
public static SourceCodeFile getCurrentlyOpenedFile() {
MainProjectManager mainProjectManager = new MainProjectManager();
Project openedProject = mainProjectManager.getMainProject();
/* Get Java file currently displaying in the IDE if there is an opened project */
if (openedProject != null) {
TopComponent activeTC = TopComponent.getRegistry().getActivated();
DataObject dataLookup = activeTC.getLookup().lookup(DataObject.class);
File file = FileUtil.toFile(dataLookup.getPrimaryFile()); // Currently opened file
// Check if the opened file is a Java file
if (FilenameUtils.getExtension(file.getAbsoluteFile().getAbsolutePath()).equalsIgnoreCase("java")) {
return new SourceCodeFile(file);
} else {
return null;
}
} else {
return null;
}
}
基本上,使用 NetBeans API,它会检测用户当前在 IDE 中打开的文件。然后,它加载它并从中创建一个 SourceCodeFile
对象。
现在我想使用 JUnit 对该方法进行单元测试。问题是不知道怎么测试。
由于它没有接收任何参数作为参数,我无法测试它在给定错误参数时的行为。我还考虑过尝试操纵 openedProject
以测试给定该对象一些不同值的方法行为,但就我而言,我不能以这种方式操纵 JUnit 中的变量。我也无法检查方法 returns,因为单元测试总是 return null,因为它没有检测到 NetBeans 中任何打开的文件。
所以,我的问题是:如何进行此方法的单元测试?
嗯,你的方法确实有参数,"between the lines":
MainProjectManager mainProjectManager = new MainProjectManager();
Project openedProject = mainProjectManager.getMainProject();
基本上获取要处理的对象。
所以第一步是将该方法签名更改为:
public static SourceCodeFile getCurrentlyOpenedFile(Project project) {
...
当然,没有使用该对象,除了空值检查。所以 下一个 级别将有一个独特的方法,如
SourceCodeFile lookup(DataObject dataLookup) {
换句话说:您真正的问题是您编写了难以测试的代码。 "default" 答案是:您必须更改生产代码,以便更容易测试。
例如,将其拆开,并将所有不同方面放入更小的辅助方法中。
你看,最后一个方法 lookup()
,它接受一个参数,现在(以某种方式)可以为此设计测试用例。可能您将不得不使用 Mockito 等模拟框架在您的测试代码中传递该 DataObject class 的 mocked 实例。
长话短说:这里没有弯路。您不能(以合理的方式)测试您的代码,因为它当前是结构化的。重新构建您的生产代码,然后您所有关于 "when I pass X, then Y should happen" 的想法都可以实现。
免责声明:是的,理论上,您可以可以 测试上述代码,方法是严重依赖 PowerMock(ito) 或 JMockit 等框架。这些框架允许您控制(模拟)调用静态方法,或new()
。所以他们会让你完全控制你方法中的一切。但这基本上会迫使您的测试知道一切 在被测方法中发生的事情。这是一件非常糟糕的事情。
我在 NetBeans 插件中使用了这个方法:
public static SourceCodeFile getCurrentlyOpenedFile() {
MainProjectManager mainProjectManager = new MainProjectManager();
Project openedProject = mainProjectManager.getMainProject();
/* Get Java file currently displaying in the IDE if there is an opened project */
if (openedProject != null) {
TopComponent activeTC = TopComponent.getRegistry().getActivated();
DataObject dataLookup = activeTC.getLookup().lookup(DataObject.class);
File file = FileUtil.toFile(dataLookup.getPrimaryFile()); // Currently opened file
// Check if the opened file is a Java file
if (FilenameUtils.getExtension(file.getAbsoluteFile().getAbsolutePath()).equalsIgnoreCase("java")) {
return new SourceCodeFile(file);
} else {
return null;
}
} else {
return null;
}
}
基本上,使用 NetBeans API,它会检测用户当前在 IDE 中打开的文件。然后,它加载它并从中创建一个 SourceCodeFile
对象。
现在我想使用 JUnit 对该方法进行单元测试。问题是不知道怎么测试。
由于它没有接收任何参数作为参数,我无法测试它在给定错误参数时的行为。我还考虑过尝试操纵 openedProject
以测试给定该对象一些不同值的方法行为,但就我而言,我不能以这种方式操纵 JUnit 中的变量。我也无法检查方法 returns,因为单元测试总是 return null,因为它没有检测到 NetBeans 中任何打开的文件。
所以,我的问题是:如何进行此方法的单元测试?
嗯,你的方法确实有参数,"between the lines":
MainProjectManager mainProjectManager = new MainProjectManager();
Project openedProject = mainProjectManager.getMainProject();
基本上获取要处理的对象。
所以第一步是将该方法签名更改为:
public static SourceCodeFile getCurrentlyOpenedFile(Project project) {
...
当然,没有使用该对象,除了空值检查。所以 下一个 级别将有一个独特的方法,如
SourceCodeFile lookup(DataObject dataLookup) {
换句话说:您真正的问题是您编写了难以测试的代码。 "default" 答案是:您必须更改生产代码,以便更容易测试。
例如,将其拆开,并将所有不同方面放入更小的辅助方法中。
你看,最后一个方法 lookup()
,它接受一个参数,现在(以某种方式)可以为此设计测试用例。可能您将不得不使用 Mockito 等模拟框架在您的测试代码中传递该 DataObject class 的 mocked 实例。
长话短说:这里没有弯路。您不能(以合理的方式)测试您的代码,因为它当前是结构化的。重新构建您的生产代码,然后您所有关于 "when I pass X, then Y should happen" 的想法都可以实现。
免责声明:是的,理论上,您可以可以 测试上述代码,方法是严重依赖 PowerMock(ito) 或 JMockit 等框架。这些框架允许您控制(模拟)调用静态方法,或new()
。所以他们会让你完全控制你方法中的一切。但这基本上会迫使您的测试知道一切 在被测方法中发生的事情。这是一件非常糟糕的事情。