Android测试:用Mockito挖掘改造

时间:2014-04-07 18:34:37

标签: java android android-studio mockito retrofit

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

在我的MainActivityTest文件中,我试图找出new OTBService().getService()方法正在进行的getApi调用,因此我可以返回MockedOTBService,将客户端更改为自定义返回json

按原样,当前实现将是MockedOTBService,如果我必须在MockedOTBService内放置一个记录器,但也会通过并调用真正的api,这在测试中不是我想要的。

我正在尝试使用Mockito存储Retrofit API调用并返回json。我似乎无法理解为什么存根被调用尚未存在问题。

备注:

  1. 我正在使用ActivityInstrumentationTestCase2
  2. 我只运行一次测试
  3. 如果我添加verify(mockedOTBService, atLeastOnce()).getService();,则说它从未被调用过。
  4. 如果我将when...thenReturn更改为使用mMainActivity = spy(getActivity()),则不会更改,并且会调用真实的API。
  5. 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'
    }
    

1 个答案:

答案 0 :(得分:6)

通过允许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();
  }
}