搜索了一段时间后,我仍然无法找到自己喜欢的答案。
我有一个Swingworker执行"长"任务,与DB交谈并返回结果。我想为此编写一个单元测试,并为我的DB一个模拟对象。
我在此处基于这篇很棒的帖子实施了我的摇摆工作者:
如何使此摇摆工具可测试
但是,它实际上没有设备测试逻辑。而且我还没有看到任何关于最佳实践的精彩文章,这使我相信我缺少一些基本的东西。是否简单地检查完成的循环检查吗?还是我应该利用更复杂的东西?还是最佳实践仅仅是为了构建对正在测试的逻辑的同步访问点?
- 编辑:我添加了Swingworker代码,以查看如何实现它。所以我的问题是:如何为此课程编写有效单元测试?
public class MovieListLoaderWorker extends SwingWorker<ArrayList<String>, ArrayList<String>> {
//private Model model;
private MovieListDB db;
private Response target;
private boolean keepAlive = false;
public MovieListLoaderWorker(MovieListDB db, Response target) {
this.db = db;
this.target = target;
}
public MovieListLoaderWorker( boolean keepAlive, MovieListDB db, Response target) {
this.db = db;
this.target = target;
this.keepAlive = keepAlive;
}
/**
* @return List of movies (synchronous)
*/
public ArrayList<String> getMovieList() {
ArrayList<String> movieNames = new ArrayList<String>(db.getMovieSet(true));
Collections.sort(movieNames);
return movieNames;
}
protected ArrayList<String> doInBackground() throws Exception {
target.started();
// if we want to keep the Thread alive, we spin and publish movie lists
while (keepAlive) {
publish(getMovieList());
Thread.sleep(Config.MOVIE_LIST_REFRESH_RATE_MILLIS);
}
// only run once, and simply return the Movie list.
return getMovieList();
}
@Override
protected void process(List<ArrayList<String>> list) {
ArrayList<String> s = list.get(list.size() - 1);
target.statusUpdate(s);
super.process(list);
}
@Override
protected void done() {
try {
ArrayList<String> movieNames = get();
if (movieNames == null) {
target.failure(new BackgroundException(new Exception("Unable to load movie names.")));
}
else {
target.success(movieNames);
}
}
catch (InterruptedException ex) {
target.failure(new BackgroundException(ex));
}
catch (ExecutionException ex) {
target.failure(new BackgroundException(ex));
}
}
public interface Response {
void started();
void statusUpdate(ArrayList<String> list);
void success(ArrayList<String> movieList);
void failure(BackgroundException ex);
}
public class BackgroundException extends Exception {
public BackgroundException(Throwable cause) {
super(cause);
}
}
}
您必须在此处清楚责任。
一个部分是必须与该数据库交谈的实际"服务",并且您想通过Swingworker运行。
我将实现该 dbservice 完全独立于线程上下文。 dbservice 类也具有 no 与Swingworker的关系。这是一个提供特定服务的"独立"类,可以完全测试单位,而不必担心Swingworker或Threads。
然后创建自己的小摇摆工人,该工厂使用该 dbservice 并使用该对象进行工作。
现在,您可以将 dbservice 的模拟实例纳入您的Swingworker;您可以使用单元测试来确保"接线"正确。
换句话说:不要将完整的功能推向摇摆工。相反,这里有单独的担忧;因为这也导致"测试需求"的分离。
因此,作为如何进行单元测试的实现,我想出的摇摆工人会感谢任何反馈。而且,如果您像我一样,难以为这个问题找到一个体面的资源,我希望它对您有所帮助。
第一个示例是利用jodah.net的服务员功能。这将迫使通话线等到摇摆工人返回。您可以在匿名响应对象中对摇摆工作者的结果进行任何必要的断言,并直接进行异常测试。
//here's the Waiter import, among others that you'll need
import net.jodah.concurrentunit.Waiter;
@Test
public void testExecute_AsyncExample1() throws Throwable {
final Waiter waiter = new Waiter();
MovieListLoaderWorker mlw = new MovieListLoaderWorker(db, new Response() {
@Override
public void success(ArrayList<String> movieList) {
waiter.assertNotNull(movieList);
waiter.assertTrue(movieList instanceof ArrayList);
waiter.assertEquals(3, movieList.size());
waiter.resume();
}
@Override
public void started() {
}
@Override
public void failure(BackgroundException ex) {
}
@Override
public void statusUpdate(ArrayList<String> list) {
}
});
mlw.execute();
waiter.await(1, TimeUnit.SECONDS);
}
第二个示例非常简单,并利用了SwingWorker.get()
块直到返回的事实。get()
返回时,Swingworker提出的例外将传递给呼叫者。
@Test
public void testExecute_AsyncExample2() throws Throwable {
MovieListLoaderWorker mlw = new MovieListLoaderWorker(db, response);
mlw.execute();
mlw.get(); //blocking so we can verify
verify(response).started();
verify(db).getMovieSet(true);
}
我为自己锻炼的两种模式。对其他意见感兴趣。