Android MockWebServer示例

示例

万一您的活动,片段和UI需要进行一些后台处理,则最好使用MockWebServer,该MockWebServer在android设备上本地运行,为您的UI带来封闭且可测试的环境。

https://github.com/square/okhttp/tree/master/mockwebserver

第一步是包括gradle依赖项:

testCompile 'com.squareup.okhttp3:mockwebserver:(insert latest version)'

现在,运行和使用模拟服务器的步骤是:

  • 创建模拟服务器对象

  • 从特定的地址和端口(通常是localhost:portnumber)启动它

  • 排队响应特定请求

  • 开始测试

在mockwebserver的github页面上对此进行了很好的解释,但是在我们的例子中,我们希望对所有测试都可以使用更好和可重用的东西,并且JUnit规则将在这里发挥作用:

/**
 *JUnit  rule that starts and stops a mock web server for test runner
*/
 public class MockServerRule extends UiThreadTestRule {

 private MockWebServer mServer;

 public static final int MOCK_WEBSERVER_PORT = 8000;

    @Override
    public Statement apply(final Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                startServer();
                try {
                    base.evaluate();
                } finally {
                    stopServer();
                }
            }
        };
    }

    /**
     * Returns the started web server instance
     *
     * @return mock server
     */
    public MockWebServer server() {
        return mServer;
    }

    public void startServer() throws IOException, NoSuchAlgorithmException {
        mServer = new MockWebServer();
        try {
            mServer(MOCK_WEBSERVER_PORT);
        } catch (IOException e) {
            throw new IllegalStateException(e,"mock server start issue");
        }
    }

    public void stopServer() {
        try {
            mServer.shutdown();
        } catch (IOException e) {
            Timber.e(e, "mock server shutdown error”);
        }
    }
}

现在,我们假设我们具有与上一个示例完全相同的活动,只是在这种情况下,当我们按下按钮应用程序时,将从网络上获取某些内容,例如:https://someapi.com/name

这将返回一些文本字符串,这些文本字符串将在快餐栏文本(例如,NAME +您输入的文本)中串联在一起。

/**
* Testing of the snackbar activity with networking.
**/
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SnackbarActivityTest{
    //意式咖啡规则,告诉您要开始哪个活动
    @Rule
    public final ActivityTestRule<SnackbarActivity> mActivityRule = 
        new ActivityTestRule<>(SnackbarActivity.class, true, false);

    //启动模拟Web服务器
    @Rule
    public final MockServerRule mMockServerRule = new MockServerRule();

    @Override
    public void tearDown() throws Exception {
       //与前面的示例相同
    }
    
    @Override
    public void setUp() throws Exception {
       //与前面的示例相同

       **//重要提示:**将您的应用程序指向您的模拟网络服务器端点,例如
       MyAppConfig.setEndpointURL("http://localhost:8000");
    }
    
    /**
    *Test methods should always start with "testXYZ" and it is a good idea to 
    *name them after the intent what you want to test
    **/
    @Test
    public void testSnackbarIsShown() {
        //设置模拟网络服务器
        mMockServerRule.server().setDispatcher(getDispatcher());

        mActivityRule.launchActivity(null);
        //检查是否显示了我们的文本输入并在其中输入一些文本
        String textToType="new snackbar text";
        onView(withId(R.id.textEntry)).check(matches(isDisplayed()));
        //我们检查的是我们的快餐栏,显示来自模拟Web服务器的文本以及我们键入的文本
        onView(withId(R.id.textEntry)).perform(typeText("JazzJackTheRabbit" + textToType));
        //点击按钮显示小吃栏
        onView(withId(R.id.shownSnackbarBtn)).perform(click());
        //断言显示了带有带有我们键入并显示的文本的snackbar_id的视图
        onView(allOf(withId(android.support.design.R.id.snackbar_text), 
        withText(textToType))) .check(matches(isDisplayed()));
    }
    
     /**
     *creates a mock web server dispatcher with prerecorded requests and responses
     **/
    private Dispatcher getDispatcher() {
        final Dispatcher dispatcher = new Dispatcher() {
            @Override
            public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
                if (request.getPath().equals("/name")){
                    return new MockResponse().setResponseCode(200)
                            .setBody("JazzJackTheRabbit");
                }
                throw new IllegalStateException("没有设置模拟 " + request.getPath());
            }
        };
        return dispatcher;
    }

我建议将调度程序包装在某种构建器中,以便您可以轻松地链接屏幕并为屏幕添加新的响应。例如

 return newDispatcherBuilder()
            .withSerializedJSONBody("/authenticate", Mocks.getAuthenticationResponse())
            .withSerializedJSONBody("/getUserInfo", Mocks.getUserInfo())
            .withSerializedJSONBody("/checkNotBot", Mocks.checkNotBot());