【问题标题】:Android Tests: Stubbing out Retrofit with MockitoAndroid 测试:使用 Mockito 去除 Retrofit
【发布时间】:2014-05-20 03:57:49
【问题描述】:

在我的MainActivity 中,我有一个名为getAPI 的方法,它返回一个OTBServiceWrapper。这用于设置改造以调用 API。

在我的MainActivityTest 文件中,我试图删除getApi 方法正在进行的new OTBService().getService() 调用,以便我可以返回一个MockedOTBService,它将客户端更改为返回json 的自定义客户端。

目前的实现将是 MockedOTBService,如果我必须在 MockedOTBService 中放置一个记录器,但也会失败并调用真正的 api,这是我不希望在测试中想要的。

我正在尝试使用 Mockito 存根 Retrofit API 调用并返回 json。我似乎无法理解为什么调用存根但没有存根有问题的方法。

注意事项:

  1. 我正在使用ActivityInstrumentationTestCase2
  2. 我只运行一项测试
  3. 如果我添加 verify(mockedOTBService, atLeastOnce()).getService(); 则表示它从未被调用过。
  4. 如果我将 when...thenReturn 更改为使用 mMainActivity = spy(getActivity()),则不会发生更改,而是调用了真正的 API。

Logcat 输出

Logger﹕ MockedOTBService was called // Mock is called
Logger﹕ Real OTBService was called // Real API is called
Logger﹕ MainActivity getAPI method class is "$Proxy1" // Mock is shown in MainActivity
Logger﹕ RealAPIResponse JSON Parsed ID: 266 // Real API response returned

真实流量

MainActivity.onCreate() > OTBService.getService() > OTBServiceWrapper.createSearch(...)

尝试在测试中实现目标

MainActivity.onCreate() > MockedOTBService.getService() > OTBServiceWrapper.createSearch(...)

MainActivity.java

public class MainActivity extends Activity {
  private OTBServiceWrapper serviceWrapper;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    getApi().createSearch(...)
  }

  public OTBServiceWrapper getApi() {
    return new OTBService().getService();
  }
}

OTBService.java

public class OTBService {
  public OTBServiceWrapper getService() {
    RestAdapter restAdapter = new RestAdapter.Builder()
        .setEndpoint(Constants.API_URL)
        .build();

    return restAdapter.create(OTBServiceWrapper.class);
  }
}

OTBServiceWrapper.java

public interface OTBServiceWrapper {
  @POST(Constants.API_SEARCHES_POST_URL)
  void createSearch(@Body Request request, Callback<Request.Response> callback);
}

MainActivityTest.java

public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
  private OTBService mMockedOTBService;
  private MainActivity mMainActivity;
  private View mSearchButton;

  public MainActivityTest() { super(MainActivity.class); }

  @Override
  protected void setUp() throws Exception {
    super.setUp();

    setActivityInitialTouchMode(true);

    System.setProperty("dexmaker.dexcache", getInstrumentation().getTargetContext().getCacheDir().getPath());

    mMockedOTBService = mock(OTBService.class);
    when(mMockedOTBService.getService()).thenReturn(new MockedOTBService(getInstrumentation().getContext()).getService());

    mMainActivity = getActivity();

    mSearchButton = mMainActivity.findViewById(R.id.AbSearchButton);
    mYourHolidayButton = mMainActivity.findViewById(R.id.AbYourHolidayButton);
  }

  public void testButtonActions() {
    TouchUtils.clickView(this, mSearchButton);
    ...
  }
}

MockedOTBService.java

public class MockedOTBService {
  private Context context;

  public MockedOTBService(Context context) { this.context = context; }

  public OTBServiceWrapper getService() {
    RestAdapter restAdapter;

    restAdapter = new RestAdapter.Builder()
        .setClient(new LocalJsonClient(context))
        .setEndpoint(Constants.API_TEST_URL)
        .build();

    return restAdapter.create(OTBServiceWrapper.class);
  }
}

LocalJsonClient.java

@SuppressLint("DefaultLocale")
public class LocalJsonClient implements Client { ... }

build.gradle

dependencies {
    androidTestCompile 'com.google.dexmaker:dexmaker:1.0'
    androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.0'
}

【问题讨论】:

    标签: java android android-studio mockito retrofit


    【解决方案1】:

    通过允许 Activity 设置服务,无需模拟您的请求。

    在您的MainActivity 中为服务创建一个类变量和一个类设置器。它需要在类范围内,以防止在您将服务设置为您想要的服务之前调用OnCreate 方法。如果您还没有设置服务,还可以创建一个实例 getter。

    在您调用 getActivity() 之前的测试中,将该服务设置为您的模拟服务。 (也许考虑将其移至支持对象)。

    MainActivity.java

    public class MainActivity extends Activity {
      private static OTBServiceWrapper serviceWrapper;
    
      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        getServiceWrapper.createSearch(...)
      }
    
      public OTBServiceWrapper getServiceWrapper() {
        if (serviceWrapper == null) {
          MainActivity.setServiceWrapper(new OTBService().getService());
        }
    
        return serviceWrapper;
      }
    
      public static void setServiceWrapper(OTBServiceWrapper serviceWrapper) {
        MainActivity.serviceWrapper = serviceWrapper;
      }
    }
    

    MainActivityTest.java

    public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
      private MainActivity mMainActivity;
    
      public MainActivityTest() { super(MainActivity.class); }
    
      @Override
      protected void setUp() throws Exception {
        super.setUp();
    
        setActivityInitialTouchMode(true);
    
        MainActivity.setServiceWrapper(
          new MockedOTBService(getInstrumentation().getContext()).getService()
        );
    
        mMainActivity = getActivity();
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-22
      相关资源
      最近更新 更多