简体   繁体   English

Android测试:用Mockito挖掘改造

[英]Android Tests: Stubbing out Retrofit with Mockito

In my MainActivity I have a method called getAPI that returns an OTBServiceWrapper . 在我的MainActivity我有一个名为getAPI的方法,它返回一个OTBServiceWrapper This is used to setup retrofit for calling to an API. 这用于设置用于调用API的改进。

In my MainActivityTest file I am trying to stub out the new OTBService().getService() call that the getApi method is making so I can return a MockedOTBService which changes the client to a custom one that return json . 在我的MainActivityTest文件中,我试图找出getApi方法正在进行的new OTBService().getService()调用,这样我就可以返回一个MockedOTBService ,它将客户端更改为返回json的自定义客户端。

As is, the current implementation will it the MockedOTBService if I had to place a logger within MockedOTBService but also falls through and calls the real api, which is not want I want in a test. MockedOTBService如果我不得不在MockedOTBService放置一个记录器但是它也会通过并调用真正的api,那么当前的实现将是MockedOTBService ,这在测试中不是我想要的。

I am trying to stub the Retrofit API calls using Mockito and return json . 我试图使用Mockito存根Retrofit API调用并返回json I cant seem to understand why the stub is being called yet is not stubbing the method in question. 我似乎无法理解为什么存根被调用尚未存在问题的方法。

Notes: 笔记:

  1. I am using ActivityInstrumentationTestCase2 我正在使用ActivityInstrumentationTestCase2
  2. I am only running one test 我只运行一次测试
  3. If I add a verify(mockedOTBService, atLeastOnce()).getService(); 如果我添加一个verify(mockedOTBService, atLeastOnce()).getService(); is says it was never called. 据说它从未被称为。
  4. If I change the when...thenReturn to use a mMainActivity = spy(getActivity()) there is not change and the real API is called. 如果我更改when...thenReturn使用mMainActivity = spy(getActivity())则没有更改并且会调用真正的API。

Logcat Output 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

Real Flow 真正的流量

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

Trying to Achieve within Tests 试图在测试中实现

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

MainActivity.java 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 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 OTBServiceWrapper.java

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

MainActivityTest.java 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 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 LocalJsonClient.java

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

build.gradle 的build.gradle

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

Remove the need for mocking your request by allowing the Activity to set the service. 通过允许Activity设置服务,无需模拟您的请求。

In your MainActivity create a class variable and a class setter for the service. MainActivity ,为服务创建一个类变量和一个类设置器。 It needs to be a at the class scope to prevent the OnCreate method being called before you have set the service to what you want it to be. 它必须是类范围,以防止在将服务设置为您希望的服务之前调用OnCreate方法。 Also create an instance getter which sets the service if you have not already. 还要创建一个实例getter来设置服务(如果还没有)。

In your test before you call getActivity() set the service to be your mock service. 在您调用getActivity()之前的测试中,将服务设置为您的模拟服务。 (Maybe think about moving this out to a support object). (也许考虑将其移到支持对象)。

MainActivity.java 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 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();
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM