在 Espresso 测试下取消或覆盖在活动中进行的 API 调用 [英] Nullifying or overriding API calls made in an Activity under an Espresso test

查看:43
本文介绍了在 Espresso 测试下取消或覆盖在活动中进行的 API 调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Activity,它在 onCreate() 生命周期方法期间执行 API 调用.如果这个调用失败(它通常会在调试或测试环境中失败),一个 ViewStub 就会膨胀,作为一个错误屏幕.这个 ViewStub 覆盖了 Activity 的其余部分.

I have an Activity which performs an API call during it's onCreate() lifecycle method. If this call fails (which it will usually fail in a debug or test environment), a ViewStub is inflated which acts as an error screen. This ViewStub covers the rest of the Activity.

这会导致在使用 Espresso 执行 UI 测试时出现问题.我希望能够取消或控制此请求的结果,以便我可以为其编写可预测的测试.

This causes problems while performing UI tests with Espresso. I'd like the ability to either nullify or control the outcome of this request, so that I can write predictable tests for it.

下面是Activity中的API代码:

Below is the API code in the Activity:

@Override                                                                                             
protected void onCreate(@Nullable Bundle savedInstanceState) {                                        

    // ...                                                  

    // Perform call                                                                                   
    viewModel.loadStuff()                                                                           
        .subscribeOn(Schedulers.io())                                                                 
        .observeOn(AndroidSchedulers.mainThread())                                                    
        .doOnSubscribe(disposable -> progressBar.setVisibility(View.VISIBLE))                         
        .doOnComplete(() -> progressBar.setVisibility(View.GONE))                                     
        .subscribe(response -> {                                              
            // Success
            // ...                                                                                         
        }, throwable -> {
            // Fail                                                                
            throwable.printStackTrace();                                                          
            errorStub.inflate();                                                                                          
        });
}

我正在编写的 Espresso 测试之一是在几秒钟后测试此 Activity 中按钮的启用状态.但是,由于上面的API调用在测试时失败,按钮被ViewStub覆盖,测试失败.

One of the Espresso tests I was writing was to test the enabled state of a button in this Activity after a few seconds. However, due to the above API call failing when under test, the button is covered by the ViewStub and the test fails.

我已经尝试通过编写自定义成功响应脚本来实现 OkHTTP3 的 MockWebServer(请注意,该应用程序使用 Retrofit,而不是直接使用 OkHTTP).但是,似乎要使用 MockWebServer 您必须使用它返回的自定义 URL,并让您的应用程序代码使用该 URL 进行调用.这意味着修改应用程序代码以适应测试代码,这是没有意义的.

I've tried implementing OkHTTP3's MockWebServer (note that the application uses Retrofit, not OkHTTP directly) by scripting a custom success response. However, it appears that to use MockWebServer you have to use the custom URL that it returns, and have your application code use that URL for it's calls. This means modifying application code to accommodate test code, which does not make sense.

我也听说过自定义 Dagger 设置可以解决这个问题.

I've also heard of custom Dagger setups to work around this problem.

问题:

  1. 如何设置我的测试,以便可以取消或控制在 ActivityonCreate 方法中执行的 API 调用?
  2. 如果 MockWebServer 适合用于这种情况,我如何在不修改应用程序代码的情况下使用它?
  1. How can I setup my test so that the API call performed in the Activity's onCreate method can be nullified or controlled?
  2. If MockWebServer is the correct thing to use for this case, how can I use it without modifying application code?

感谢与此问题相关的一般评论和提示.

General comments and tips related to this question are appreciated.

推荐答案

如何设置我的测试,以便 API 调用在Activity 的 onCreate 方法可以作废或控制吗?

How can I setup my test so that the API call performed in the Activity's onCreate method can be nullified or controlled?

看来您的 viewModel.loadStuff() 已硬连线到某个预先定义的 URL.为了使其可测试,我会在创建视图模型期间将 url 作为参数传递或将其传递给 loadStuff 方法.我将演示第二个选项.
下一个问题是我们如何在测试期间更改 url?一种方法是将 url 存储在 Application 实例中并覆盖测试值.

It seems your viewModel.loadStuff() is hardwired to some pre-defiend URL. To make it testable I would pass the url as parameter during viewmodel creation or pass it to the loadStuff method. I'll demonstrate the second option.
The next question is how can we change the url during testing? One way to do it is to store the url in Application instance and override the value for testing.

1.创建保存 url 值的应用程序类.

class MyApplication extends Application {
    private static final String DEFAULT_URL = "http://yourdomain.com/api";
    private String url;

    @Override
    void onCreate() {
        super.onCreate();

        url = DEFAULT_URL;
    }

    public String getUrl() {
        return url;
    }

    @VisibleForTesting
    public void setUrl(String newUrl) {
        url = newUrl
    }
}

2.从您的活动中解析网址值

@Override                                                                                             
protected void onCreate(@Nullable Bundle savedInstanceState) {                                        
    // resolve url value
    String url = ((MyApplication) getApplication()).getUrl();                                         

    // Perform call                                                                                   
    viewModel.loadStuff(url)                                                                           
        .subscribeOn(Schedulers.io())                                                                 
        .observeOn(AndroidSchedulers.mainThread())                                                    
        .doOnSubscribe(disposable -> progressBar.setVisibility(View.VISIBLE))                         
        .doOnComplete(() -> progressBar.setVisibility(View.GONE))                                     
        .subscribe(response -> {                                              
            // Success
            // ...                                                                                         
        }, throwable -> {
            // Fail                                                                
            throwable.printStackTrace();                                                          
            errorStub.inflate();                                                                                          
        });
}

3.在您的测试中,您可以覆盖 URL 以使用 MockWebServer 的 URL.

// Espresso Test
public class ActivityTest {

  @Before
    public void setUp() throws Exception {
        MockWebServer webServer = new MockWebServer();
        HttpUrl url = webServer.url("/");

        // set the url to point to mock webserver in localhost
        MyApplication app = (MyApplication) InstrumentationRegistry.getTargetContext().getApplicationContext();
        app.setUrl(url.toString());
    }

    ....
}

您也可以使用共享首选项来存储您的服务器 url 并在测试期间覆盖该值,但想法是相同的:您的视图模型不应该硬连接到某个 URL,而是应该将 URL 注入到视图模型中.而对于解决这样的依赖,Dagger 是一个不错的选择.

You can also use shared preference to store your server url and override the value during test, but the idea is same: Your view model should not be hardwired to certain URL, but instead inject the URL to the view model. And for resolving dependency like this, Dagger is a good option.

这篇关于在 Espresso 测试下取消或覆盖在活动中进行的 API 调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆