检测单元类测试 - 无法在未调用 Looper.prepare() 的线程内创建处理程序

Gra*_*son 12 java testing junit android

抱歉,我已经查看了所有地方的教程,但没有找到我正在寻找的答案。我现在正在关注谷歌的教程:https : //developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html

我正在尝试创建一个 Instrumented 测试,当我运行它时出现错误: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

所以我的测试如下:

    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"));
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图在主要活动中运行一个方法如下(这是一个摘录):

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();
    }
Run Code Online (Sandbox Code Playgroud)

我认为这是一个问题,因为我没有正确启动服务或其他什么 - 我已经尝试使用多种方法,但我到处都遇到错误。在这里搜索,这个错误很流行,但与测试无关,所以想知道是否有人可以指出正确的方向,以便我可以测试此类中的方法?

Dav*_*son 10

发生错误是因为Looper未为您的被测系统正确设置 ( MainActivity)。

虽然ActivityFragment等有没有参数的构造,它们被设计成由Android操作系统,因此呼叫被实例化MainActivity = new Activity()是不够的,获得全业务杀星用实例完整HandlerLooper

如果您想继续测试,有两种选择:

  1. 如果你想测试一个真实的 Activity 实例,它必须是一个插装单元测试androidTest不是test),这@TestRule将导致 Android 操作系统正确实例化一个 Activity 实例:

    @Rule
    public ActivityTestRule<MainActivity> mActivityRule =
        new ActivityTestRule(MainActivity.class);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果您希望继续编写在 IDE 中运行的本地单元测试,您可以使用Robolectric。Robolectric 将正确地存根影子活动上的行为,以便您可以测试依赖Looper等的组件。请注意,其中涉及一些设置。


Hit*_*ahu 8

我就是这样解决的。我使用在主线程上运行测试用例runOnMainSync。这是完整的解决方案:

@RunWith(AndroidJUnit4::class)
class AwesomeViewModelTest {

    @Test
    fun testHandler() {

        getInstrumentation().runOnMainSync(Runnable {
            val context = InstrumentationRegistry.getInstrumentation().targetContext

            // Here you can call methods which have Handler

        })
    }
}
Run Code Online (Sandbox Code Playgroud)

Java 语法是:

getInstrumentation().runOnMainSync(() -> {
    Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
    // ...
});
Run Code Online (Sandbox Code Playgroud)