且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在测试中压倒一切的调试模块

更新时间:2023-01-23 17:19:42

我已经远远做到了这一点(我不能完全肯定这将规模尚)是在我的测试中创建一个静态测试模块类。

  @Module(
            注射= {
                    共享preferences.class
    })      静态类TestModule {
            @Provides @Singleton共享preferences provideShared preferences(){
                返回Mockito.mock(共享preferences.class);
            }
    }

和在设置()方法我注入测试模块

  @Before
    公共无效设置(){
        。ObjectGraph.create(新TestModule())注入(本);
}

然后我@Inject嘲笑类:

  @Inject共享preferences共享preferences;

I have a Gradle app with a project structure similar to Jake Wharton's u2020:

/src
    /androidTest
    /debug
    /main
    /release

In my application class I build the Dagger graph and inject it:

MyApplication extends Application {
      ...
      public void buildObjectGraphAndInject() {
          Object[] modules = Modules.list(this);
          mApplicationGraph = ObjectGraph.create(modules);
          mApplicationGraph.inject(this);
      }
      ...
}

Inside the debug sourceset, I define Modules.list() as:

public final class Modules {
  public static Object[] list(MyApplication app) {
    return new Object[] {
        new AppModule(app),
        new DebugAppModule()
    };
  }

  private Modules() {
    // No instances.
  }
}

Inside the release sourceset, I define the same thing minus the DebugAppModule:

public final class Modules {
  public static Object[] list(MyApplication app) {
    return new Object[] {
            new AppModule(app)
    };
  }

  private Modules() {
    // No instances.
  }
}

Deeper down my dependency graph, I create a MockRestAdapter that I can use when running the debug version:

@Module(
    complete = false,
    library = true,
    overrides = true
)
public final class DebugApiModule {

  @Provides @Singleton Endpoint provideEndpoint(@ApiEndpoint StringPreference apiEndpoint) {
    return Endpoints.newFixedEndpoint(apiEndpoint.get());
  }

  @Provides @Singleton MockRestAdapter provideMockRestAdapter(RestAdapter restAdapter, SharedPreferences preferences) {
    MockRestAdapter mockRestAdapter = MockRestAdapter.from(restAdapter);
    AndroidMockValuePersistence.install(mockRestAdapter, preferences);
    return mockRestAdapter;
  }

  @Provides @Singleton MyApi provideMyApi(RestAdapter restAdapter, MockRestAdapter mockRestAdapter,
                                          @IsMockMode boolean isMockMode, MockMyApi mockService) {
    if (isMockMode) {
      return mockRestAdapter.create(MyApi.class, mockService);
    }
    return restAdapter.create(MyApi.class);
  }

}

But while I'm running tests, I would like to override the DebugApiModule with a TestApiModule that looks like this:

@Module(
    complete = false,
    library = true,
    overrides = true
)
public final class TestApiModule {

  @Provides @Singleton Endpoint provideEndpoint(@ApiEndpoint StringPreference apiEndpoint) {
    return Endpoints.newFixedEndpoint(apiEndpoint.get());
  }

  @Provides @Singleton MockRestAdapter provideMockRestAdapter(RestAdapter restAdapter, SharedPreferences preferences) {
    MockRestAdapter mockRestAdapter = MockRestAdapter.from(restAdapter);
    mockRestAdapter.setDelay(0);
    mockRestAdapter.setErrorPercentage(0);
    mockRestAdapter.setVariancePercentage(0);
    return mockRestAdapter;
  }

  @Provides @Singleton MyApi provideMyApi(MockRestAdapter mockRestAdapter, MockHnApi mockService) {
      return mockRestAdapter.create(MyApi.class, mockService);
  }

}

What's the best way to accomplish this? Do I need to create a TestAppModule like this:

public final class Modules {
  public static Object[] list(MyApplication app) {
    return new Object[] {
        new AppModule(app),
        new TestAppModule()
    };
  }

  private Modules() {
    // No instances.
  }
}

And replace all of the DebugFooModule with TestFooModules? If so, how do I get around the fact that Modules.java is duplicated? Or am I way off base?

EDIT: SOLUTION

What I ended up doing is replacing the Application-level graph (where the MockRestAdapter gets created) during my test setUp

protected void setUp() throws Exception {
  super.setUp();
  HnApp app = HnApp.getInstance();
  app.buildObjectGraphAndInject(TestModules.list(app));
  getActivity();
}

What I've done this far (and I'm not entirely sure this will scale yet) is create a static test module class in my tests.

   @Module(
            injects = {
                    SharedPreferences.class
    })

      static  class TestModule {
            @Provides @Singleton SharedPreferences provideSharedPreferences(){
                return Mockito.mock(SharedPreferences.class);
            }
    }

And in the setup() method I inject the test module

  @Before
    public  void setUp(){
        ObjectGraph.create(new TestModule()).inject(this);
}

I then @Inject the mocked class:

@Inject SharedPreferences sharedPreferences;