How to write a UT for a Runnable java class which has an infinite loop in run()?
I have a java class like below. Its job is monitor a file, if that file's size does not change at certain interval, it will raise alert.
I'd like to write two UTs for it.
1.Simulates the file size keeps unchanges.
2.Simulate file size keeps changes for a while. After that file size will change.
The UT will verify alerter.alert() or alerter.harmless() is really invoked when condition is or isn't met. I mocked Alerter and passed it to Task's constructor. But how to control the timing for run()? I know timing for multi-thread cannot be controlled accurately. I just would like 开发者_如何学Pythonto know what is the best practice to write ut for this kind of class. If possible, please write a test sample.
You can regard that "some condition" as checking if a specified file's size changes at a certain interval. If not changed, some condition will be true.
class Task implements Runnable{
Alerter alerter;
boolean stop=false;
public Task(Alerter alerter){
this.alerter=alerter;
}
public void run() {
while (!stop){
if (some condition){
alerter.alert();
} else{
alerter.harmless();
}
Thread.sleep(5000);
}
}
public synchronized void stop(){
stop=true;
}
}
I'm thinking of writing uts like below. But I don't think it is good enough.
@Test
public void testRunWithFeed() {
Alerter mockAlerter=mock(Alerter.class);
Task task=new Task(mockAlerter);
Thread thread =new Thread(task);
thread.start();
try {
Thread.sleep(1000); // give Task.run() a change to run
} catch (InterruptedException e) {
e.printStackTrace();
}
task.stop();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
verify(mockAlerter,atLeastOnce()).alert();
verify(mockAlerter,never()).harmless();
}
@Test
public void testRunNoFeed() {
Alerter mockAlerter=mock(Alerter.class);
Task task=new Task(mockAlerter);
Thread thread =new Thread(task);
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
changeFileSize();
try {
Thread.sleep(6000); //because every 5000ms file size will be checked once in run()
} catch (InterruptedException e) {
e.printStackTrace();
}
task.stop();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
verify(mockAlerter,atLeastOnce()).alert();
verify(mockAlerter,atLeastOnce()).harmless();
}
Thanks in advance.
I think that you should not call sleep() and obviously should not call stop in your test. If you task runs and is expected to terminate calling join() is enough: your main thread will wait until the worker thread is done. Then you will verify the result.
And yet another tip. You should prevent your test from being stuck. Both JUnit and TestNG have annotations that define the test timeout. If timeout is expired the test will be killed by framework and will fail automatically.
For example for JUnit it is the attribute timout
: @Test(timeout=3000)
means 3 seconds.
精彩评论