2015/06/23

MortarScopeのためのMock

Mortarを採用したプロジェクトでは各所でMortarScopeが必要になる.
MortarScopeはContext.getSystemServiceを経由して取得されるが, InstrumentationRegistry.getTargetContext()で取得できるContextにはこれが実装されていないためMockオブジェクトを用意する必要がある.

以下はMotar/PresenterをテストするためのMortar/Viewのmockクラス.
MortarScopeを生成するためオリジナルのContextをContext.getSystemServiceのMock Methodを実装したContextWrapperでラップする.

あとはお決まりのEnter/ExitScope処理を実装すればMockは完成する.

private static class Viewer implements MyPresenter.MyViewer {
  private Context context;
  private MortarScope mortarScope;
  private MyPresenter presenter;

  public Viewer(Context context, MyPresenter presenter) {
    // MortarScopeを返すラッパーを定義する. 
    this.context = new ContextWrapper(context) {
      @Override
      public Object getSystemService(String name) {
        return mortarScope != null && mortarScope.hasService(name) ?
            mortarScope.getService(name) : super.getSystemService(name);
      }
    };
    this.presenter = presenter;
  }

  public void onCreate() {
    // お決まりのスコープ定義とEnterScope処理. 
    String scopeName = "UnitTestScope";
    mortarScope = MortarScope.buildRootScope().build("Root").buildChild()
        .withService(BundleServiceRunner.SERVICE_NAME, new BundleServiceRunner())
        .withService(ObjectGraphService.SERVICE_NAME, ObjectGraph.create(new AppHomeModule()))
        .build(scopeName);
    BundleServiceRunner.getBundleServiceRunner(getContext()).onCreate(null);

    presenter.takeView(this);
  }

  public void onDestroy() {
    // お決まりのExitScope処理. 
    presenter.dropView(this);
  }

  // MyPresenter.MyViewerの抽象メソッドを実装
  @Override
  public Context getContext() {
    return context;
  }
}

Mortar/Viewの生成と破棄はsetup/tearDownで実装した.

@Before
public void setup() throws Exception {
  presenter = new MyPresenter();
  viewer = new Viewer(InstrumentationRegistry.getTargetContext(), presenter);
  viewer.onCreate();
}

@After
public void tearDown() {
  viewer.onDestroy();
}

以上.