啄木鸟软件测试培训网:www.3testing.com
本文来自:领测软件测试网
本章使用Robolectric+powermock测试多线程的场景。
首先,我们看一下,被测试的类的源码,HelloThread的init方法主要功能是启动一个线程,然后在新线程内部做实际初始化,实际初始化完毕后将初始化状态标志为成功或者失败,在本场景里将状态标志为失败。在非多线程的场景中,我们进行单元测试时,通常直接对被测试函数的返回值做校验,而多线程场景中,因为实际功能在另外一条线程里完成,所以对函数的返回值做校验并没有实际价值,但是我们可以通过校验日志来看执行效果。
被测试的类的源码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
publicclassHelloThread {privateInitStatus mInitStatus =InitStatus.INIT;privatestaticfinalStringTAG =HelloThread.class.getSimpleName();publicenumInitStatus {INIT, INITING, OK, FAILED }privateHelloThread(){}privatestaticclassHelloThreadHolder {privatestaticHelloThread sInstance =newHelloThread();}publicstaticHelloThread getInstance(){returnHelloThreadHolder.sInstance;}publicsynchronizedvoidinit(){if(mInitStatus ==InitStatus.INIT){mInitStatus =InitStatus.INITING;newThread(){@Override publicvoidrun(){internalInit();}}.start();}}privatevoidinternalInit(){System.out.println("========< start init ===>>>");try{doSomething();setInitStatus(InitStatus.OK);}catch(Throwablee){System.out.println("========< init failed ===>>>");//初始化失败后打印日志,这也是我们写程序时时常见的一种做法,//通过日志能帮助程序员更好地定位问题SLog.e(TAG, "init failed");setInitStatus(InitStatus.FAILED);}System.out.println("========< finish init ===>>>");}privatesynchronizedvoidsetInitStatus(InitStatus status){mInitStatus =status;notifyAll();}publicsynchronizedvoidwaitForInitFinished()throwsInterruptedException{while(mInitStatus ==InitStatus.INITING){wait();}}privatevoiddoSomething()throwsInterruptedException{Thread.sleep(3500);//假设初始化失败thrownewRuntimeException("som exception");}}
展开全文
从代码中可以看到我们在初始化失败时,会打印error日志,这也让我们的校验有了可行性。通过前述章节,我们知道可以对SLog做静态partial mock, 然后在测试init时,收集执行数据,最后对SLog进行校验,看其是否打印了指定的error日志即可。 测试代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
@RunWith(RobolectricGradleTestRunner.class)@Config(constants =BuildConfig.class, sdk =21)//必须写如下代码 让PowerMock 忽略Robolectric的所有注入@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})//因为我们是针对类做静态函数的mock,所以必须使用PrepareForTest说明我们要mock的类@PrepareForTest({SLog.class})publicclassHelloThreadTest {//不可缺少的代码 表明使用Powermock执行单元测试,虽然我们使用的是RoblectricGradleTestRunner来执行单元测试//但是添加了如下代码后RoblectricGradleTestRunner会调用PowerMock的TestRunner去执行单元测试@Rule publicPowerMockRule rule =newPowerMockRule();@Before publicvoidsetup(){PowerMockito.mockStatic(SLog.class);}@Test publicvoidtestInit()throwsException{PowerMockito.spy(SLog.class);HelloThread.getInstance().init();HelloThread.getInstance().waitForInitFinished();//因为我们在被测试代码里调用了SLog.e 日志, 所以verifyStatic 必然失败PowerMockito.verifyStatic(times(0));SLog.e(HelloThread.class.getSimpleName(), "init failed");}}
执行结果如下所示:
可以看到使用PowerMock 对 多线程程序做校验是非常方便的
我的淘宝课:
https://item.taobao.com/item.htm?spm=2013.1.0.0.QQT3Ey&id=534580861824&buyerDetail=true
顾翔凡言:
这几天大雨,被淹的是新城、新街道,高速公路。没淹的是紫禁城、明城墙、古城。作为测试的人,我们需要好好思考质量二字。
啄木鸟软件测试培训中心,主打五门课:
初级:
1,你也想成为软件测试工程师吗~软件测试基础教程
中级:
2,软件测试工程师必须掌握的技能~软件测试设计方法实战。
高级:
3,让你的程序跑得更快~软件性能测试
4,让你找出更多的bug~探索式软件测试
5,让用户迷上你的产品~用户体验式测试