MockWebServer 示例
如果你的活动,片段和 UI 需要一些后台处理,那么使用的好东西是 MockWebServer,它在 Android 设备上运行 localy,为你的 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{
//espresso rule which tells which activity to start
@Rule
public final ActivityTestRule<SnackbarActivity> mActivityRule =
new ActivityTestRule<>(SnackbarActivity.class, true, false);
//start mock web server
@Rule
public final MockServerRule mMockServerRule = new MockServerRule();
@Override
public void tearDown() throws Exception {
//same as previous example
}
@Override
public void setUp() throws Exception {
//same as previous example
**//IMPORTANT:** point your application to your mockwebserver endpoint e.g.
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() {
//setup mockweb server
mMockServerRule.server().setDispatcher(getDispatcher());
mActivityRule.launchActivity(null);
//check is our text entry displayed and enter some text to it
String textToType="new snackbar text";
onView(withId(R.id.textEntry)).check(matches(isDisplayed()));
//we check is our snackbar showing text from mock webserver plus the one we typed
onView(withId(R.id.textEntry)).perform(typeText("JazzJackTheRabbit" + textToType));
//click the button to show the snackbar
onView(withId(R.id.shownSnackbarBtn)).perform(click());
//assert that a view with snackbar_id with text which we typed and is displayed
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("no mock set up for " + request.getPath());
}
};
return dispatcher;
}
我建议将调度程序包装在某种类型的 Builder 中,这样你就可以轻松地为你的屏幕链接并添加新的响应。例如
return newDispatcherBuilder()
.withSerializedJSONBody("/authenticate", Mocks.getAuthenticationResponse())
.withSerializedJSONBody("/getUserInfo", Mocks.getUserInfo())
.withSerializedJSONBody("/checkNotBot", Mocks.checkNotBot());