So I am working on this little project that uses Dagger 2 for dependency injection and Realm as a database.
I am unit testing it with Robolectric and Mockito (with Powermock). From previous research (and a lot of pain) I realised testing Realm is pretty laborious, but has been done in the past here.
Now, my project has a very similar setup and structure to the one linked above.
When I run my unit tests, all of them pass except for one that gives me a very cryptic message that looks as follows:
java.lang.NullPointerException
at org.robolectric.internal.ShadowExtractor.extract(ShadowExtractor.java:5)
at org.robolectric.Shadows.shadowOf(Shadows.java:1190)
at org.robolectric.shadows.CoreShadowsAdapter.getMainLooper(CoreShadowsAdapter.java:37)
at org.robolectric.util.ComponentController.<init>(ComponentController.java:31)
at org.robolectric.util.ComponentController.<init>(ComponentController.java:23)
at org.robolectric.util.ActivityController.<init>(ActivityController.java:40)
at org.robolectric.util.ActivityController.of(ActivityController.java:32)
at org.robolectric.Robolectric.buildActivity(Robolectric.java:82)
at org.robolectric.Robolectric.buildActivity(Robolectric.java:78)
at org.robolectric.Robolectric.setupActivity(Robolectric.java:86)
at uk.co.placona.tradesafe.view.EditActivityTest.ActivityShouldNotBeNull(EditActivityTest.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.powermock.modules.junit4.internal.impl
The line of code specified on the error above is:
activity = Robolectric.setupActivity(EditActivity.class);
The activity exists, and has a TradeRepository injected to it when it starts up.
The activity in question can be found here along with the rest of the code. I have been trying to debug this for about 3 days now with no success. Every other unit test I create works fine, except any unit test that is used by an Activity, which makes me think I'm probably missing something really obvious.
Would be happy to clarify any questions here. With many thanks!
static is evil, powermock is evil :).
I think you should get rid of your class Injector. You don't need it because you have only one CustomApplication object during the lifetime of your application.
You should modify your code as follow:
In CustomApplication.java, the application component is created, set in a field variable, and injected
private ApplicationComponent applicationComponent;
public void setup(){
getOrCreateApplicationComponent().inject(this);
databaseRealm.setup();
stethoDebug.setup(this);
}
public ApplicationComponent getOrCreateApplicationComponent() {
if (applicationComponent == null) {
applicationComponent = DaggerApplicationComponent.builder()
.applicationContextModule(new ApplicationContextModule(this))
.repositoryModule(new RepositoryModule())
.build();
}
return applicationComponent;
}
In the methods onCreate of CreateActivity, EditActivity, and MainActivity, Injector is replaced with
((CustomApplication) getApplication())
.getOrCreateApplicationComponent()
.inject(this);
In RepositoryModule we will use Dagger 2 to inject dependencies into constructors so we don't need to inject manually the Context and the DatabaseRealm
#Provides
#Singleton
public TradeRepository provideTradeRepository(DatabaseRealm databaseRealm) {
return new TradeRepositoryImpl(databaseRealm);
}
#Provides
#Singleton
public DatabaseRealm provideDatabaseRealm(Context context) {
return new DatabaseRealm(context);
}
then in DatabaseRealm we add a constructor with Context as parameter
Context mContext;
RealmConfiguration realmConfiguration;
public DatabaseRealm(Context context) {
mContext = context;
}
and same in TradeRepositoryImpl, a constructor with databaseRealm is added
DatabaseRealm databaseRealm;
public TradeRepositoryImpl(DatabaseRealm databaseRealm) {
this.databaseRealm = databaseRealm;
}
For RepositoryTestModule, we add databaseRealm as parameter:
#Provides
#Singleton
public TradeRepository provideTradeRepository(DatabaseRealm databaseRealm) {
return isMocked ? mock(TradeRepository.class) : new TradeRepositoryImpl(databaseRealm);
}
in your TestCustomApplication we override the getOrCreateApplicationComponent
#Override
public ApplicationComponent getOrCreateApplicationComponent() {
return DaggerApplicationComponentTest.builder()
.applicationContextModuleTest(new ApplicationContextModuleTest())
.repositoryModuleTest(new RepositoryModuleTest(false))
.build();
}
Now for each of your tests we run them with RobolectricGradleTestRunner and add TestCustomApplication.class as application tag
#RunWith(RobolectricGradleTestRunner.class)
#Config(constants = BuildConfig.class, sdk = 21, application = TestCustomApplication.class)
when we need to inject dependencies into ours tests we will inject like this:
#Before
public void setupDagger() {
DaggerApplicationComponentTest.builder()
.applicationContextModuleTest(new ApplicationContextModuleTest())
.repositoryModuleTest(new RepositoryModuleTest(false))
.build().inject(this);
}
We still have a NullPointerException in our EditActivityTest because this line:
loadTrade(intent.getExtras().getString("ID"));
Either you check the intent is not null or you provide one in your test.
Looking to your test class, I don't see that you use any of Robolectric test runners.
You must use RobolectricGradleTestRunner or RobolectricTestRunner to trigger Robolecric functionality about loading manifest, parsing resources, creating main looper, etc.
If you don't use them, you probably can achieve it with own code in setup, but it is not the usual way, and I'm not sure that many people here can explain to you how to achieve it.
As well, Robolectric and PowerMock are modifying java ClassLoader both. That is why it is so hard (maybe impossible) to get them together working. So check #Steve answer how to modify your code to remove PowerMock necessity for your test.
Related
We used RoboGuice, but it's deprecated I start replace it with Dagger2.
// https://github.com/google/dagger
compile('com.google.dagger:dagger:2.7')
annotationProcessor 'com.google.dagger:dagger-compiler:2.7'
provided 'org.glassfish:javax.annotation:10.0-b28'
#Module
public class ApplicationModule {
Application mApp;
public ApplicationModule(#NonNull Application app) {
Preconditions.checkNotNull(app);
mApp = app;
}
#Provides
#Singleton
public SharedPreferences providesSharedPrefs() {
return PreferenceManager.getDefaultSharedPreferences(mApp);
}
#Provides
#Singleton
public DateHelper providesDateHelper() {
return new DateHelper(mApp);
}
#Provides
#Singleton
public PersistentConfig providesPersistentConfig() {
return new PersistentConfig(mApp);
}
#Provides
#Singleton
public OttoBus providesOttoBus() {
return new OttoBus();
}
}
public class Application extends MultiDexApplication {
private ApplicationComponent mApplicationComponent;
#Override
public void onCreate() {
super.onCreate();
mApplicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
mApplicationComponent.inject(this);
}
public static Application getApp(#NonNull Context context) {
return (Application) context.getApplicationContext();
}
public static ApplicationComponent getApplicationComponent(#NonNull Context context) {
return getApp(context).getApplicationComponent();
}
}
And after everywhere when I want to inject ApplicationComponent
For example MainActivity
public class MainActivity extends AppCompatActivity {
#Inject
PersistentConfig mPersistentConfig;
#Inject
OttoBus mOttoBus;
#Override
public void onCreate(Bundle savedInstanceState) {
Helper.manageRotation(this);
super.onCreate(null);
setContentView(R.layout.main_layout);
Application.getApplicationComponent(this).inject(this);
}
}
Application.getApplicationComponent(context).inject(this);
First question: I'm really confused about interface ApplicationComponent which must provide all activities/fragments/services (etc) where I want to use injection. But I can't use generic objects like Activity / Fragment. Or am I really out of reality and don't understand how Dagger2 works?
Because this is really crazy for project with about 50+ activities and a tons of fragments/services...
#Singleton
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void inject(#NonNull Application app);
void inject(#NonNull MainActivity object);
void inject(#NonNull DispatcherActivity object);
void inject(#NonNull DateTimeHelper object);
void inject(#NonNull DatabaseHelper object);
void inject(#NonNull LandingPageActivityFragment object);
void inject(#NonNull RedirectActivity object);
void inject(#NonNull CategoryFragment object);
void inject(#NonNull BaseModuleFragment object);
void inject(#NonNull NotificationHelper object);
void inject(#NonNull RecordAdapter object);
void inject(#NonNull PagingProvider object);
void inject(#NonNull FilterDialog object);
... next 100+ injections?
}
Said me, that it can't be real...
Second question: How I can provide to inject generic classes, when I can't use it like void inject(#NonNull NotificationHelper<? extends GenericObject> object); because it require specific object. So I must write all this objects inside ApplicationComponent and not use ? notation?
It's a much more than just crazy :(. Maybe better stay with RoboGuice which is much more developer friendly and don't need make this overhead and manual check every injected objects? When I forgot add them to this list, I will get NPE in runtime (when I will not test it a lot it will crash customers).
It's much faster write it manually, than make a list of all object when it's not possible to use generic objects like Activity / Fragment / Service.
Is there a better solution, when I don't want use same generic BaseActivity which will inject every part of ApplicationModule and every activity will be extended by this huge BaseActivity?
This question has aspects of a complaint, but to attempt an answer:
I'm really confused about interface ApplicationComponent which must provide all activities/fragments/services (etc) where I want to use injection. But I can't use generic objects like Activity / Fragment. Or am I really out of reality and don't understand how Dagger2 works?
This is, indeed, how Dagger 2 works; it you must statically supply the type of the injection target inside the injector (component) and you cannot use 'generic' (covariant) types. Dagger 2 does this in order to maintain a DI framework that is 100% static.
Note that you are specifying RecordAdapter and DatabaseHelper as injection sites. You probably don't need to do that, you should try and only specify top level objects for which the constructor is not visible (Activity, Fragment, and Service) as injection sites. The rest of the objects should be able to be constructed through annotating their dependencies with #Inject and specifying their dependencies, if any, in a Module.
Maybe better stay with RoboGuice which is much more developer friendly and don't need make this overhead and manual check every injected objects
Yes Roboguice is more friendly in the sense that you don't have to worry about specifying the injection targets. However, consider the following in Roboguice: 1. The 'red stacktrace of death' you get when you set up your object graph incorrectly
2. The fact that you cannot get see which implementations of interfaces are actually being used in your project with Find Usages which can also be 'developer unfriendly'
Is there a better solution, when I don't want use same generic BaseActivity which will inject every part of ApplicationModule and every activity will be extended by this huge BaseActivity?
Well, it would depend which dependencies you are using and where. If you have a small list of dependencies that you want to inject everywhere, that may be the best solution i.e., make a BaseActivity that receives injection of these and makes this available to all of your subclasses. Alternatively, you can use sub-components and modules you can divide up your object graph so that you can group consumers/injection targets together with the correct modules. Then you don't need to have one 'god' component that lists all of the injection sites.
Second question: How I can provide to inject generic classes, when I can't use it like void inject(#NonNull NotificationHelper object); because it require specific object. So I must write all this objects inside ApplicationComponent and not use ? notation?
Yes, you must supply the invariant type of the injection target. I am not sure if your NotificationHelper<String> is a top level type. Why not inject it through the object graph when you inject in a Fragment, Activity or Service?
If it absolutely must be an injection target you will need to subclass: NotificationHelper<String> and Notification<Integer> become StringNotificationHelper extends NotificationHelper<String>, IntegerNotficationHelper extends NotificationHelper<Integer>. This is a practice recommended in the book Clean Code.
You don't need to write it all the injection sites inside the ApplicationComponent, you may create subcomponents that correspond with the consumption patterns of the dependencies in your project.
(disclosure: as someone who is currently trying to migrate a project from Roboguice to Dagger 2 I am sympathetic to your complaint)
Thanks, we solved it as you described a week ago. Using every objects as injected.
Better solution for it is don't use only inject but complex name. Why? Because it will help to resolve why some object is not injected (you know, base classes and so on).
#Singleton
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void injectApplication(#NonNull Application app);
void injectMainActivity(#NonNull MainActivity object);
void injectDispatcherActivity(#NonNull DispatcherActivity object);
...
}
We finally use for genericity UtilityWrapper as is described here: https://medium.com/#patrykpoborca/dagger-2-and-base-classes-generics-and-presenter-injection-7d82053080c#.b58ykd4cm
I have a question regarding Android Dagger 2 und the usage of #Inject and #Provide annotations. Given are the following two simplified examples:
public class A {
String msg;
public A(String msg){
this.msg = msg;
}
}
public class B {
public A a;
public B(A a){
this.a = a;
}
}
#Module
public class AModule {
#Provides
A providesA(){
return new A("blah");
}
#Provides
B ProvidesB(A a)
{
return new B(a);
}
}
The example is pretty straight forward, I have two methods in my AModule with #Provides annotations. Therefore, Dagger can create an object of B using an instance of A with the string blah.
My second example looks like this:
public class A {
String msg;
public A(String msg){
this.msg = msg;
}
}
public class B {
public A a;
#Inject
public B(A a){
this.a = a;
}
}
#Module
public class AModule {
#Provides
A providesA(){
return new A("blah");
}
}
In this example, Dagger can create an instance of B because an object A can be created using AModule. The instance of B can be created because it's constructor uses the #Inject annotation.
So my question is: What's the difference between those two examples? Both seem to have the same semantics. Does the generated code differ and are there any pitfalls? Or is it just a matter or personal taste or best practices?
They work similarly, and the #Inject style is preferred when you have such an easy choice like in your example. However, this isn't always the case:
If B, which consumes A, is not under your control and not DI-aware, you will have no way to add the #Inject annotation.
If B is an interface, you will need #Provides (or #Binds in newer Dagger versions) to identify which implementation to use.
If you choose not to use your Dagger object graph for every injected parameter, you can call the constructor manually whether it is marked #Inject or not. This might be the case if you want a specific instance or constant as a constructor parameter, but you can't or don't want to set up the binding for the whole object graph.
#Provides allows you to effectively create a factory method, with everything that allows. This is a great way to change which instances are included in your graph, or to effectively add to the class's constructor graph-wide if you can't (or shouldn't) change the class itself.
You can return an existing instance rather than a new one. Note that custom scopes (implemented in Dagger through subcomponents) might be a better fit for common cases, but if you have more complex instance control or use a third-party library that controls instances, you could put that into your factory method.
If you want your binding to return null sometimes that logic can live in a #Provides method. Make sure you annotate the injection sites as #Nullable.
You can choose between implementations with a factory method like a #Provides method, particularly if the choice depends on runtime environment.
You can run post-construction logic, including instance registration or initialization.
This is my code:
#Mock
MyApplication application;
#Before
public void setup() {
application = Mockito.mock(MyApplication .class);
}
#Test
public void createProducts() {
application.ormLiteDatabaseHelper.getProductDao().create(new Product());
}
I get a NullPointerException at this line. My Application class inits the OrmLiteDatabaseHelper in its onCreate, how do I access the ormLiteDatabaseHelper from the mocked version of MyApplication?
application is a "mock" object. It only pretents to be a "MyApplication". Thus the only thing it can return for the method ormLiteDatabaseHelper is null and thus calling getProductDao on that will fail with a NullPointerException.
If you want it to return anything, then you need to tell your mock that, for example by...
OrmLiteDatabaseHelper ormLiteDatabaseHelper = ..something...;
Mockito.when( application.ormLiteDatabaseHelper ).thenReturn ( ormLiteDatabaseHelper);
Only then will your mock know to return something else than null. Of course, there are other ways, but for starters... Perhaps you also need partial mocking, which would be explained here, but without further info, it's hard to say.
Also, if you write #Mock, then you should either use the correct #RunWith annotation or call MockitoAnnotations.initMocks(this); instead of creating the mock manually via Mockito.mock. If you want to use the later, you don't need the #Mock annotation.
TL;DR;
Is it acceptable for a class to depend on the ObjectGraph itself?
I need this because I need to inject dependencies on some objects that I load at runtime - at a time that is disconnected from the point at which the ObjectGraph is initialized. Here is an example that illustrates how I use ServiceLoader framework to load concrete implementation classes of a Service at runtime, and then inject dependencies into the loaded implementation classes.
interface Plugin {
void doSomething();
}
class AwesomePlugin implements plugin {
#Inject DependencyOne dependencyOne;
#Inject DependencyTwo dependencyTwo;
void doSomething(){
// ...some implementation...
}
}
class PluginEngine{
public void start(){
ServiceLoader<Plugin> pluginLoader = ServiceLoader.load(Plugin.class);
for(Plugin plugin: pluginLoader){
//TODO: Inject plugin dependencies here
}
}
}
Doing this would require the PluginEngine class to have access to the ObjectGraph instance:
class PluginEngine{
private final ObjectGraph objectGraph;
public PluginEngine(ObjectGraph graph){
this.objectGraph = graph;
}
public void start(){
ServiceLoader<Plugin> pluginLoader = ServiceLoader.load(Plugin.class);
for(Plugin plugin: pluginLoader){
objectGraph.inject(plugin);
}
}
}
Is this a code smell? Is this pointing to some problem elsewhere in my code, or in the way my dependencies are set up?
While composing this question, I began to see the role of Dagger as a means of replacing arbitrary dependencies with a dependency on the ObjectGraph itself. On Android, you use a reference to the custom Application sub-class and use it to perform injection - which is basically just a means to get access to the ObjectGraph itself. Is this reasoning flawed?
To answer my own question, it looks like this is acceptable. The u2020 sample app does something roughly similar. In fact it makes some very clever use of getSystemService() to achieve this but that is Android specific. In particular, look at Injector.java and how it is used from within custom views like TrendingView
So, conceptually, one could do something like this - which basically abstracts the concrete ObjectGraph dependency behind an Injector interface.
class PluginEngine{
private final Injector injector;
public PluginEngine(Injector injector){
this.injector = injector;
}
public void start(){
ServiceLoader<Plugin> pluginLoader = ServiceLoader.load(Plugin.class);
for(Plugin plugin: pluginLoader){
injector.inject(plugin);
}
}
}
This can be refined/adjusted in various ways such that the injector dependency is provided via a constructor or obtained in other ways.
I've recently gone whole-hog with Dagger because the concept of DI makes complete sense. One of the nicer "by-products" of DI (as Jake Wharton put in one of his presentations) is easier testability.
So now I'm basically using Espresso to do some functional testing, and I want to be able to inject dummy/mock data to the application and have the activity show them up. I'm guessing since, this is one of the biggest advantages of DI, this should be a relatively simple ask. For some reason though, I can't seem to wrap my head around it. Any help would be much appreciated. Here's what I have so far (I've written up an example that reflects my current setup):
public class MyActivity
extends MyBaseActivity {
#Inject Navigator _navigator;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyApplication.get(this).inject(this);
// ...
setupViews();
}
private void setupViews() {
myTextView.setText(getMyLabel());
}
public String getMyLabel() {
return _navigator.getSpecialText(); // "Special Text"
}
}
These are my dagger modules:
// Navigation Module
#Module(library = true)
public class NavigationModule {
private Navigator _nav;
#Provides
#Singleton
Navigator provideANavigator() {
if (_nav == null) {
_nav = new Navigator();
}
return _nav;
}
}
// App level module
#Module(
includes = { SessionModule.class, NavigationModule.class },
injects = { MyApplication.class,
MyActivity.class,
// ...
})
public class App {
private final Context _appContext;
AppModule(Context appContext) {
_appContext = appContext;
}
// ...
}
In my Espresso Test, I'm trying to insert a mock module like so:
public class MyActivityTest
extends ActivityInstrumentationTestCase2<MyActivity> {
public MyActivityTest() {
super(MyActivity.class);
}
#Override
public void setUp() throws Exception {
super.setUp();
ObjectGraph og = ((MyApplication) getActivity().getApplication()).getObjectGraph().plus(new TestNavigationModule());
og.inject(getActivity());
}
public void test_SeeSpecialText() {
onView(withId(R.id.my_text_view)).check(matches(withText(
"Special Dummy Text")));
}
#Module(includes = NavigationModule.class,
injects = { MyActivityTest.class, MyActivity.class },
overrides = true,
library = true)
static class TestNavigationModule {
#Provides
#Singleton
Navigator provideANavigator() {
return new DummyNavigator(); // that returns "Special Dummy Text"
}
}
}
This is not working at all. My Espresso tests run, but the TestNavigationModule is completely ignored... arr... :(
What am I doing wrong? Is there a better approach to mocking modules out with Espresso? I've searched and seen examples of Robolectric, Mockito etc. being used. But I just want pure Espresso tests and need to swap out a module with my mock one. How should i be doing this?
EDIT:
So I went with #user3399328 approach of having a static test module list definition, checking for null and then adding it in my Application class. I'm still not getting my Test injected version of the class though. I have a feeling though, its probably something wrong with dagger test module definition, and not my espresso lifecycle. The reason I'm making the assumption is that I add debug statements and find that the static test module is non-empty at time of injection in the application class. Could you point me to a direction of what I could possibly be doing wrong. Here are code snippets of my definitions:
MyApplication:
#Override
public void onCreate() {
// ...
mObjectGraph = ObjectGraph.create(Modules.list(this));
// ...
}
Modules:
public class Modules {
public static List<Object> _testModules = null;
public static Object[] list(MyApplication app) {
// return new Object[]{ new AppModule(app) };
List<Object> modules = new ArrayList<Object>();
modules.add(new AppModule(app));
if (_testModules == null) {
Log.d("No test modules");
} else {
Log.d("Test modules found");
}
if (_testModules != null) {
modules.addAll(_testModules);
}
return modules.toArray();
}
}
Modified test module within my test class:
#Module(overrides = true, library = true)
public static class TestNavigationModule {
#Provides
#Singleton
Navigator provideANavigator()() {
Navigator navigator = new Navigator();
navigator.setSpecialText("Dummy Text");
return navigator;
}
}
With Dagger 2 and Espresso 2 things have indeed improved. This is how a test case could look like now. Notice that ContributorsModel is provided by Dagger. The full demo available here: https://github.com/pmellaaho/RxApp
#RunWith(AndroidJUnit4.class)
public class MainActivityTest {
ContributorsModel mModel;
#Singleton
#Component(modules = MockNetworkModule.class)
public interface MockNetworkComponent extends RxApp.NetworkComponent {
}
#Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
MainActivity.class,
true, // initialTouchMode
false); // launchActivity.
#Before
public void setUp() {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
RxApp app = (RxApp) instrumentation.getTargetContext()
.getApplicationContext();
MockNetworkComponent testComponent = DaggerMainActivityTest_MockNetworkComponent.builder()
.mockNetworkModule(new MockNetworkModule())
.build();
app.setComponent(testComponent);
mModel = testComponent.contributorsModel();
}
#Test
public void listWithTwoContributors() {
// GIVEN
List<Contributor> tmpList = new ArrayList<>();
tmpList.add(new Contributor("Jesse", 600));
tmpList.add(new Contributor("Jake", 200));
Observable<List<Contributor>> testObservable = Observable.just(tmpList);
Mockito.when(mModel.getContributors(anyString(), anyString()))
.thenReturn(testObservable);
// WHEN
mActivityRule.launchActivity(new Intent());
onView(withId(R.id.startBtn)).perform(click());
// THEN
onView(ViewMatchers.nthChildOf(withId(R.id.recyclerView), 0))
.check(matches(hasDescendant(withText("Jesse"))));
onView(ViewMatchers.nthChildOf(withId(R.id.recyclerView), 0))
.check(matches(hasDescendant(withText("600"))));
onView(ViewMatchers.nthChildOf(withId(R.id.recyclerView), 1))
.check(matches(hasDescendant(withText("Jake"))));
onView(ViewMatchers.nthChildOf(withId(R.id.recyclerView), 1))
.check(matches(hasDescendant(withText("200"))));
}
Your approach doesn't work because it only happens once, and as Matt mentioned, when the activity's real injection code runs, it will wipe out any variables injected by your special object graph.
There are two ways to get this to work.
The quick way: make a public static variable in your activity so a test can assign an override module and have the actual activity code always include this module if it's not null (which will only happen in tests). It's similar to my answer here just for your activity base class instead of application.
The longer, probably better way: refactor your code so that all activity injection (and more importantly graph creation) happens in one class, something like ActivityInjectHelper. In your test package, create another class named ActivityInjectHelper with the exact same package path that implements the same methods, except also plusses your test modules. Because test classes are loaded first, your application will execute with the testing ActivityInjectHelper. Again it's similar to my answer here just for a different class.
UPDATE:
I see you've posted more code and it's close to working, but no cigar. For both activities and applications, the test module needs to be snuck in before onCreate() runs. When dealing with activity object graphs, anytime before the test's getActivity() is fine. When dealing with applications, it's a bit harder because onCreate() has already been called by the time setUp() runs. Luckily, doing it in the test's constructor works - the application hasn't been created at that point. I briefly mention this in my first link.
The call to getActivity will actually start your activity calling onCreate in the process which means you won't be getting your test modules added to the graph in time to be used. Using activityInstrumentationTestcase2 you can't really inject properly at the activity scope. I've worked around this by using my application to provide dependencies to my activities and then inject mock objects into it which the activities will use. It's not ideal but it works. You can use an event bus like Otto to help provide dependencies.
EDIT: the below in post form http://systemdotrun.blogspot.co.uk/2014/11/android-testing-with-dagger-retrofit.html
To test an Activity using Espresso + Dagger I have done the below
Inspired by the answer from #user3399328 I have a DaggerHelper class inside my Application class, which allows the test case to override the #Providers using Test #Modules which supply mocks. As long as
1) This is done before the testCases getActivity() call is made (as my inject call happens in my activity inside Activity.onCreate)
2) tearDown removes the test modules from the object graph.
Examples below.
Note: this is not ideal as this is subject to similar pitfalls of using factory methods for IoC but at least this way its only ever a single call in tearDown() to bring the system under test back to normal.
The DaggerHelper inside my Application class
public static class DaggerHelper
{
private static ObjectGraph sObjectGraph;
private static final List<Object> productionModules;
static
{
productionModules = new ArrayList<Object>();
productionModules.add(new DefaultModule());
}
/**
* Init the dagger object graph with production modules
*/
public static void initProductionModules()
{
initWithModules(productionModules);
}
/**
* If passing in test modules make sure to override = true in the #Module annotation
*/
public static void initWithTestModules(Object... testModules)
{
initWithModules(getModulesAsList(testModules));
}
private static void initWithModules(List<Object> modules)
{
sObjectGraph = ObjectGraph.create(modules.toArray());
}
private static List<Object> getModulesAsList(Object... extraModules)
{
List<Object> allModules = new ArrayList<Object>();
allModules.addAll(productionModules);
allModules.addAll(Arrays.asList(extraModules));
return allModules;
}
/**
* Dagger convenience method - will inject the fields of the passed in object
*/
public static void inject(Object object) {
sObjectGraph.inject(object);
}
}
My Test module inside my test class
#Module (
overrides = true,
injects = ActivityUnderTest.class
)
static class TestDataPersisterModule {
#Provides
#Singleton
DataPersister provideMockDataPersister() {
return new DataPersister(){
#Override
public void persistDose()
{
throw new RuntimeException("Mock DI!"); //just a test to see if being called
}
};
}
}
Test method
public void testSomething()
{
MyApp.DaggerHelper.initWithTestModules(new TestDataPersisterModule());
getActivity();
...
}
Tear down
#Override
public void tearDown() throws Exception
{
super.tearDown();
//reset
MyApp.DaggerHelper.initProductionModules();
}