万一您的活动,片段和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());