Testing Android devices with multiple threads

I have a problem with unit tests in Android.

My MyObject has a start() method as follows:

 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(); } 

And I want to check that onStart () is being called. So I tried something like this:

 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()); } 

But this will not work, I think this is because it is in the Handler and in the new thread.

My test class extends AndroidTestCase. What should I do? What is the best practice for this case?

Sincerely.

+6
source share
2 answers

When I encounter testing some multithreaded code, I try to let the program make the most of its natural flow. In addition, I avoid using sleep operators, since you do not receive any guarantees that the sleep interval you have chosen is sufficient for the subject to complete what he is doing; you often have to choose too long time intervals, and this leads to a much slower execution of your test cases.

I would recommend that you try adding code to the tested class, in this case MyObject , which calls the listener whenever something happens. Apparently you already have callback methods for onStart() and onStop() (if these are events / callbacks), so they should be called, and you should use them to control the flow of your test. When you get the onStart() event, you must call stop() and wait for the onStop() event.

Update

First of all, you have redundant code:

 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(); } 

Either start a new thread to call onStart() , or pay runnable in the handler thread queue.

Version 1- remove the handler and just let the code be executed in a new thread:

 public void start() { new Thread() { @Override public void run() { super.run(); mIsRunning = true; onStart(); } }.start(); } 

Version 2- uses a handler to asynchronously execute a callback:

 public void start() { final Handler onStartHandler = new Handler(); onStartHandler.post(new Runnable() { @Override public void run() { mIsRunning = true; onStart(); } }); } 

And secondly: I noticed that if you do not have a Looper , then whatever you send with the Handler will be ignored (thus, it will never be called). For more information on the Looper-Handler pattern, see Article: Android Guts: An Introduction to Loopers and Handlers . Looper and Handler are assumed to be attached to the same thread (usually the main thread). In addition, if you create a Handler in a separate thread as your Looper , then you will encounter the same problem: everything that you publish using Handler will be ignored.

Here are some more helpful questions and articles about loopers and handlers:

The relationships between Looper, Handler and MessageQueue are shown below: enter image description here

+7
source

The problem is that you call onStart (), which calls the new thread, and then immediately asks if it is running. There is a start time for a new thread, and while this is happening, your test asks if it is running - it is not YET.

I bet if you waited using Thread.sleep () or a loop, you will find that it is running "in the end".

What are you really trying to verify?

If you need a new thread, you can familiarize yourself with the threads, synchronize, etc. http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html

0
source

Source: https://habr.com/ru/post/898987/


All Articles