Android单元测试多个线程

lou*_*uio 6 multithreading android unit-testing handler

我在Android中进行单元测试时遇到问题.

我的对象MyObject有一个start()这样的方法:

public void start() {
    final Handler onStartHandler = new Handler();
    new Thread() {
        @Override
        public void run() {
            super.run();

            onStartHandler.post(new Runnable() {
                @Override
                public void run() {
                    mIsRunning = true;
                    onStart();
                }
            });
        }
    }.start();
}
Run Code Online (Sandbox Code Playgroud)

我想测试onStart()是否被调用.所以我尝试了类似的东西:

public void testOnStartIsCalled() {
    assertFalse("onStart() should not be called", mMyObject.isRunning());
    mMyObject.start();
    assertTrue("onStart() should be called", mMyObject.isRunning());
    mMyObject.stop();
    assertFalse("onStop() should be called", mMyObject.isRunning());
}
Run Code Online (Sandbox Code Playgroud)

但它不起作用,我想这是因为它在Handler和一个新线程中.

我的测试类扩展了AndroidTestCase.我该怎么办 ?这种情况的最佳做法是什么?

问候.

Kir*_*ril 9

当我处理测试一些多线程代码时,我试图让程序尽可能多地采用自然流程.另外,我避免使用睡眠陈述,因为你没有得到任何保证,你选择的睡眠间隔足以让你的测试对象完成它正在做的事情; 你经常最终不得不选择太大的睡眠间隔,这会迫使你的测试用例执行得慢得多.

我建议您尝试将一些代码添加到您正在测试的类中,在这种情况下MyObject,只要发生某些事情就会调用侦听器.看来你已经有了回调方法onStart()onStop()(如果那些是事件/回调),所以应该调用它们,你应该使用它们来控制你的测试流程.当您收到onStart()活动时,您应该打电话stop()并等待onStop()活动.

更新

首先,您有冗余代码:

public void start() {
    final Handler onStartHandler = new Handler();
    new Thread() {
        @Override
        public void run() {
            super.run();

            onStartHandler.post(new Runnable() {
                @Override
                public void run() {
                    mIsRunning = true;
                    onStart();
                }
            });
        }
    }.start();
}
Run Code Online (Sandbox Code Playgroud)

启动一个新线程来调用onStart()或调度Handler的线程队列上的runnable.

版本1-删除处理程序,只需让代码在新线程中执行:

public void start() {
    new Thread() {
        @Override
        public void run() {
            super.run();
            mIsRunning = true;
            onStart();
        }
    }.start();
}
Run Code Online (Sandbox Code Playgroud)

版本2-仅使用处理程序异步执行回调:

public void start() {
    final Handler onStartHandler = new Handler();

    onStartHandler.post(new Runnable() {
        @Override
        public void run() {
            mIsRunning = true;
            onStart();
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

第二:我注意到如果你没有一个Looper,那么你发布的任何内容Handler都会被忽略(因此它永远不会被调用).有关Looper-Handler模​​式的更多信息,请参阅文章:Android Guts:Loopers和Handler简介.的LooperHandler都应该被连接到同一个线程(通常是主线程).另外,如果您在Handler单独的线程上创建Looper,那么您将遇到同样的问题:您发布的任何内容都Handler将被忽略.

这里有一些关于loopers和handlers的更好的问题和文章:

Looper,Handler和MessageQueue之间的关系如下所示: 在此输入图像描述