当需要测试此程序时,哪种方式应该更好
首先askUserPathAndWord()
要求用户输入path
和whatFind
。我们有两个主题:
put()
。 take()
,并在其中查找whatFind
文件。如果搜索成功,则输出以控制该文件的路径
以及这个词的频率。这是与多线程工作的集成依赖性。哪种变体能更好地测试这个程序--Sunit of EasyMock?我阅读了一些关于EasyMock的教程,但我不知道在哪些情况下最好使用它。
代码:
class FolderScan implements Runnable {
private String path;
private BlockingQueue<File> queue;
private CountDownLatch latch;
private File endOfWorkFile;
FolderScan(String path, BlockingQueue<File> queue, CountDownLatch latch,
File endOfWorkFile) {
this.path = path;
this.queue = queue;
this.latch = latch;
this.endOfWorkFile = endOfWorkFile;
}
public FolderScan() {
}
@Override
public void run() {
findFiles(path);
queue.add(endOfWorkFile);
latch.countDown();
}
private void findFiles(String path) {
try {
File root = new File(path);
File[] list = root.listFiles();
for (File currentFile : list) {
String s = currentFile.getName().toLowerCase();
if (currentFile.isDirectory()) {
findFiles(currentFile.getAbsolutePath());
} else {
if (s.matches("^.*?\\.(txt|pdf|doc|docx|html|htm|xml|djvu|rar|rtf)$")) {
queue.put(currentFile);
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class FileScan implements Runnable {
private String whatFind;
private BlockingQueue<File> queue;
private CountDownLatch latch;
private File endOfWorkFile;
public FileScan(String whatFind, BlockingQueue<File> queue,
CountDownLatch latch, File endOfWorkFile) {
this.whatFind = whatFind;
this.queue = queue;
this.latch = latch;
this.endOfWorkFile = endOfWorkFile;
}
public FileScan() {
}
@Override
public void run() {
while (true) {
try {
File file;
file = queue.take();
if (file == endOfWorkFile) {
break;
}
scan(file);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
latch.countDown();
}
private void scan(File file) {
Scanner scanner = null;
int matches = 0;
try {
scanner = new Scanner(file);
} catch (FileNotFoundException e) {
System.out.println("File Not Found.");
e.printStackTrace();
}
while (scanner.hasNext())
if (scanner.next().equals(whatFind)) {
matches++;
}
if (matches > 0) {
String myStr = String.format(
"File: %s - and the number of matches " + "is: %d",
file.getAbsolutePath(), matches);
System.out.println(myStr);
}
}
public void askUserPathAndWord() {
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(System.in));
String path;
String whatFind;
BlockingQueue<File> queue = new LinkedBlockingQueue<File>();
try {
System.out.println("Please, enter a Path and Word"
+ "(which you want to find):");
System.out.println("Please enter a Path:");
path = bufferedReader.readLine();
System.out.println("Please enter a Word:");
whatFind = bufferedReader.readLine();
if (path != null && whatFind != null) {
File endOfWorkFile = new File("GameOver.tmp");
CountDownLatch latch = new CountDownLatch(2);
FolderScan folderScan = new FolderScan(path, queue, latch,
endOfWorkFile);
FileScan fileScan = new FileScan(whatFind, queue, latch,
endOfWorkFile);
Executor executor = Executors.newCachedThreadPool();
executor.execute(folderScan);
executor.execute(fileScan);
latch.await();
System.out.println("Thank you!");
} else {
System.out.println("You did not enter anything");
}
} catch (IOException | RuntimeException e) {
System.out.println("Wrong input!");
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println("Interrupted.");
e.printStackTrace();
}
}
public static void main(String[] args) {
new FileScan().askUserPathAndWord();
}
}
问题:
EasyMock
,我们应该如何正确地做到这一点?Junit
,我们如何测试void
方法?答案 0 :(得分:2)
JUnit还是EasyMock? - 答案是,两者都有!一个是单元测试框架,另一个是允许模拟对象,这使您可以编写更好的测试。因此,使用JUnit plus 任何模拟框架(建议EasyMock
,我使用Mockito
或者第三个名为jMock
)是个好主意。< / p>
哪种测试具有最佳覆盖率? - 模拟允许您关注要进行单元测试的代码区域,因此您最终将比以前测试更多代码。模拟执行繁重操作的代码(例如写入数据库或从文件系统读取 - 与您的操作一样)特别有用。因此,将EasyMock与JUnit结合使用可以比单独的JUnit更好地覆盖(和更好的测试)。
如何更好地测试两种变体中的合同义务? - 确保所有公共方法都经过测试。然后,在每次测试结束时彻底断言并验证您的期望。
如果答案是EasyMock,我们应该如何正确地执行此操作? - 使用verify
方法检查测试期间是否正确调用了模拟对象。
如果是Junit,我们如何测试void方法? - 你需要以其他方式断言结果是预期的。也许您将对象作为参数传递给void方法,或者可能有另一种方法来获取结果(例如getter)。
祝你好运!答案 1 :(得分:2)
在考虑测试此程序时,请记住单元测试是什么。从Wikipedia开始,“单元测试是一种方法,通过该方法测试各个源代码单元......以确定它们是否适合使用”。
请记住,您正在深入了解一下,因为测试多线程程序很困难。您应尽可能地从测试功能中删除线程交互的复杂性。
看看你的程序,你已经有了很好的封装和关注点分离,所以你很顺利。我的策略是独立于线程测试两个*Scan
对象。为此,请记住他们的角色是什么。我会说以下内容:
FolderScan
遍历目录结构,查找特定类型的文件,并将通过过滤器的文件放入队列。当它耗尽目录结构时,它会将特定文件放入队列中,倒计时锁存并退出。FileScan
使用文件队列,对它们执行操作,并将输出打印到控制台。当它命中特定文件时,它会倒计时并退出。由于你已经有了大概或多或少的工作代码,当你对其进行改进测试时(而不是在编写代码时编写它们,这是更好的)你想要尽可能少地更改源代码以获得通过测试。之后你可能希望重构代码,你的测试会让你有信心这样做。
FolderScan测试
首先,为FolderScan
创建一个新的JUnit测试。您可以编写多个测试,但是从高级别开始,每个测试都应该使用一些文件填充目录结构。我至少会测试每一个案例:
测试越精细,越好。每个测试只是创建一个FolderScan
的新实例,为它指定指定给定文件夹的参数。调用run(),并确保:
File
个对象。CountDownLatch
已经减少。File
。FileScan测试
在高级别,现在应该清楚测试:创建一些文本File
对象,用它们填充队列并使用标记,然后将它们传递给新的FileScan对象。再次,更精细,更好,至少:
这个课程存在问题,这是经典的“如何测试单身人士”问题。实际上,此对象的结果是通过管道传送到System.out
,您必须先将其挂钩以检查结果。作为第一遍,我建议重构构造函数以传递PrintStream
。在制作中你会传入System.out
,在测试中你会传递一些你可以检查的内容:new PrintStream(new ByteArrayOutputStream())
你可以检查内容,或者更好的是模拟。
最后,每个测试都要检查:
CountDownLatch
已经减少PrintStream
已写入预期内容。您应该非常有信心FileScan
和FolderScan
的工作方式与宣传的一样。
*测试askUserPathAndWord *
我没有看到任何直接的方法来测试这个函数/类。它违反了Single Responsibility Principle,只是做了太多事情。我会将以下职责提取到新方法或类中:
FileScan
(工厂)FolderScan
ExecutorService
,排队,然后等待闩锁然后你可以独立测试它们。
*后续步骤*
进行这些测试的一个好处是,一旦你拥有它们,你就可以自由地进行重构,并确信你没有破坏它们。例如,您可以查看Callable
而不是Runnable
,这可以让您处理Future
引用,从FolderScan
中删除输出参数,并删除{{ 1}}完全。
快乐测试!