Sorry I've looked at tutorials all over the place and not found the answer I'm looking for. I'm following Google's Tutorial at the moment here: https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html
I'm trying to create an Instrumented test and when I run it I'm getting the error : java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
So my test is as follows:
package testapp.silencertestapp;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class MainActivityTest {
private MainActivity testMain;
@Before
public void createActivity(){
testMain = new MainActivity();
}
@Test
public void checkFancyStuff(){
String time = testMain.createFancyTime(735);
assertThat(time, is("07:35"));
}
}
And I'm trying to run a method inside the main activity is as follows (this is an extract):
public class MainActivity extends AppCompatActivity {
private TimePicker start;
private TimePicker end;
@Override
protected void onCreate(Bundle savedInstanceState) {
start = (TimePicker) findViewById(R.id.startPicker);
end = (TimePicker) findViewById(R.id.endPicker);
}
String createFancyTime(int combinedTime) {
StringBuilder tempString = new StringBuilder(Integer.toString(combinedTime));
if(tempString.length()==4){
tempString = tempString.insert(2, ":");
}
else if (tempString.length()==3){
tempString = tempString.insert(1, ":");
tempString = tempString.insert(0, "0");
}
else if(tempString.length()==2){
tempString = tempString.insert(0, "00:");
}
else if(tempString.length()==1){
tempString = tempString.insert(0, "00:0");
}
return tempString.toString();
}
I presume that this is an issue because I'm not starting the service up correctly or something - I've tried using several ways, but I just get errors everywhere. Searching on here and this error is popular, but not in relation to testing, so wondered if anyone could kindly point me in the right direction so I can test the methods in this class?
This is how I solved it. I ran test case on main thread using runOnMainSync
. Here is the comlete solution:
@RunWith(AndroidJUnit4::class)
class AwesomeViewModelTest {
@Test
fun testHandler() {
getInstrumentation().runOnMainSync(Runnable {
val context = InstrumentationRegistry.getInstrumentation().targetContext
// Here you can call methods which have Handler
})
}
}
The error is happening because the Looper
is not correctly set up for your system under test (MainActivity
).
While Activity
, Fragment
etc. have no-args constructors, they are designed to be instantiated by the Android OS and as such calling MainActivity = new Activity()
is not enough to obtain a fully-operational death star instance complete with Handler
and Looper
.
There are two options if you want to proceed with testing:
If you want to test a real instance of an Activity it will have to be an instrumented unit test (androidTest
not test
) and the @TestRule
will cause the Android OS to correctly instantiate an instance of Activity:
@Rule
public ActivityTestRule<MainActivity> mActivityRule =
new ActivityTestRule(MainActivity.class);
If you would prefer to keep writing local unit tests that run in the IDE you can use Robolectric. Robolectric will correctly stub behaviour on a shadow Activity so that you can test components that rely on Looper
etc. Note there is some setup involved.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With