Android Unit Tests with Dagger 2 - java

I have an Android app that uses Dagger 2 for dependency injection. I am also using the latest gradle build tools that allow a build variant for unit testing and one for instrumentation tests. I am using java.util.Random in my app, and I want to mock this for testing. The classes I'm testing don't use any Android stuff, so they're just regular java classes.
In my main code I define a Component in a class that extends the Application class, but in the unit tests I'm not using an Application. I tried defining a test Module and Component, but Dagger won't generate the Component. I have also tried using the Component that I defined in my application and swapping the Module when I build it, but the application's Component doesn't have inject methods for my test classes. How can I provide a mock implementation of Random for testing?
Here's some sample code:
Application:
public class PipeGameApplication extends Application {
private PipeGame pipeGame;
#Singleton
#Component(modules = PipeGameModule.class)
public interface PipeGame {
void inject(BoardFragment boardFragment);
void inject(ConveyorFragment conveyorFragment);
}
#Override
public void onCreate() {
super.onCreate();
pipeGame = DaggerPipeGameApplication_PipeGame.create();
}
public PipeGame component() {
return pipeGame;
}
}
Module:
#Module
public class PipeGameModule {
#Provides
#Singleton
Random provideRandom() {
return new Random();
}
}
Base class for tests:
public class BaseModelTest {
PipeGameTest pipeGameTest;
#Singleton
#Component(modules = PipeGameTestModule.class)
public interface PipeGameTest {
void inject(BoardModelTest boardModelTest);
void inject(ConveyorModelTest conveyorModelTest);
}
#Before
public void setUp() {
pipeGameTest = DaggerBaseModelTest_PipeGameTest.create(); // Doesn't work
}
public PipeGameTest component() {
return pipeGameTest;
}
}
or:
public class BaseModelTest {
PipeGameApplication.PipeGame pipeGameTest;
// This works if I make the test module extend
// the prod module, but it can't inject my test classes
#Before
public void setUp() {
pipeGameTest = DaggerPipeGameApplication_PipeGame.builder().pipeGameModule(new PipeGameModuleTest()).build();
}
public PipeGameApplication.PipeGame component() {
return pipeGameTest;
}
}
Test Module:
#Module
public class PipeGameTestModule {
#Provides
#Singleton
Random provideRandom() {
return mock(Random.class);
}
}

This is currently impossible with Dagger 2 (as of v2.0.0) without some workarounds. You can read about it here.
More about possible workarounds:
How do you override a module/dependency in a unit test with Dagger 2.0?
Creating test dependencies when using Dagger2

You have hit the nail on the head by saying:
application's Component doesn't have inject methods for my test classes
So, to get around this problem we can make a test version of your Application class. Then we can have a test version of your module. And to make it all run in a test, we can use Robolectric.
1) Create the test version of your Application class
public class TestPipeGameApp extends PipeGameApp {
private PipeGameModule pipeGameModule;
#Override protected PipeGameModule getPipeGameModule() {
if (pipeGameModule == null) {
return super.pipeGameModule();
}
return pipeGameModule;
}
public void setPipeGameModule(PipeGameModule pipeGameModule) {
this.pipeGameModule = pipeGameModule;
initComponent();
}}
2) Your original Application class needs to have initComponent() and pipeGameModule() methods
public class PipeGameApp extends Application {
protected void initComponent() {
DaggerPipeGameComponent.builder()
.pipeGameModule(getPipeGameModule())
.build();
}
protected PipeGameModule pipeGameModule() {
return new PipeGameModule(this);
}}
3) Your PipeGameTestModule should extend the production module with a constructor:
public class PipeGameTestModule extends PipeGameModule {
public PipeGameTestModule(Application app) {
super(app);
}}
4) Now, in your junit test's setup() method, set this test module on your test app:
#Before
public void setup() {
TestPipeGameApp app = (TestPipeGameApp) RuntimeEnvironment.application;
PipeGameTestModule module = new PipeGameTestModule(app);
app.setPipeGameModule(module);
}
Now you can customize your test module how you originally wanted.

In my opinion you can approach this problem by looking at it from a different angle. You will easily be able to unit test your class by not depending upon Dagger for construction class under test with its mocked dependencies injected into it.
What I mean to say is that in the test setup you can:
Mock the dependencies of the class under test
Construct the class under test manually using the mocked dependencies
We don't need to test whether dependencies are getting injected correctly as Dagger verifies the correctness of the dependency graph during compilation. So any such errors will be reported by failure of compilation. And that is why manual creation of class under test in the setup method should be acceptable.
Code example where dependency is injected using constructor in the class under test:
public class BoardModelTest {
private BoardModel boardModel;
private Random random;
#Before
public void setUp() {
random = mock(Random.class);
boardModel = new BoardModel(random);
}
#Test
...
}
public class BoardModel {
private Random random;
#Inject
public BoardModel(Random random) {
this.random = random;
}
...
}
Code example where dependency is injected using field in the class under test (in case BoardModel is constructed by a framework):
public class BoardModelTest {
private BoardModel boardModel;
private Random random;
#Before
public void setUp() {
random = mock(Random.class);
boardModel = new BoardModel();
boardModel.random = random;
}
#Test
...
}
public class BoardModel {
#Inject
Random random;
public BoardModel() {}
...
}

If you are using dagger2 with Android, you can use app flavours for providing mocking resources.
See here for a demo of flavours in mock testing(without dagger):
https://www.youtube.com/watch?v=vdasFFfXKOY
This codebase has an example:
https://github.com/googlecodelabs/android-testing
In your /src/prod/com/yourcompany/Component.java
you provide your production components.
In your /src/mock/com/yourcompany/Component.java
you provide your mocking components.
This allows you create builds of your app with or without mocking.
It also allows parallel development (backend by one team, frontend app by another team), you can mock until api methods are avilable.
How my gradle commands look (its a Makefile):
install_mock:
./gradlew installMockDebug
install:
./gradlew installProdDebug
test_unit:
./gradlew testMockDebugUnitTest
test_integration_mock:
./gradlew connectedMockDebugAndroidTest
test_integration_prod:
./gradlew connectedProdDebugAndroidTest

I actually had the same issue and found a very simple solution.
This is not the best possible solution I think but it will solve your problem.
Create a similar class in your app module:
public class ActivityTest<T extends ViewModelBase> {
#Inject
public T vm;
}
Then, in your AppComponent add:
void inject(ActivityTest<LoginFragmentVM> activityTest);
Then you will be able to inject that in your test class.
public class HelloWorldEspressoTest extends ActivityTest<LoginFragmentVM> {
#Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule(MainActivity.class);
#Test
public void listGoesOverTheFold() throws InterruptedException {
App.getComponent().inject(this);
vm.email.set("1234");
closeSoftKeyboard();
}
}

Related

How to reuse Testcontainers between multiple SpringBootTests?

I'm using TestContainers with Spring Boot to run unit tests for repositories like this:
#Testcontainers
#ExtendWith(SpringExtension.class)
#ActiveProfiles("itest")
#SpringBootTest(classes = RouteTestingCheapRouteDetector.class)
#ContextConfiguration(initializers = AlwaysFailingRouteRepositoryShould.Initializer.class)
#TestExecutionListeners(listeners = DependencyInjectionTestExecutionListener.class)
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
#Tag("docker")
#Tag("database")
class AlwaysFailingRouteRepositoryShould {
#SuppressWarnings("rawtypes")
#Container
private static final PostgreSQLContainer database =
new PostgreSQLContainer("postgres:9.6")
.withDatabaseName("database")
.withUsername("postgres")
.withPassword("postgres");
But now I have 14 of these tests and every time a test is run a new instance of Postgres is spun up. Is it possible to reuse the same instance across all tests? The Singleton pattern doesn't help since every test starts a new application.
I've also tried testcontainers.reuse.enable=true in .testcontainers.properties and .withReuse(true), but that didn't help.
You can't use the JUnit Jupiter annotation #Container if you want to have reusable containers. This annotation ensures to stop the container after each test.
What you need is the singleton container approach, and use e.g. #BeforeAll to start your containers. Even though you then have .start() in multiple tests, Testcontainers won't start a new container if you opted-in for reusability using both .withReuse(true) on your container definition AND the following .testcontainers.properties file in your home directory:
testcontainers.reuse.enable=true
A simple example might look like the following:
#SpringBootTest
public class SomeIT {
public static GenericContainer postgreSQLContainer = new PostgreSQLContainer().
withReuse(true);
#BeforeAll
public static void beforeAll() {
postgreSQLContainer.start();
}
#Test
public void test() {
}
}
and another integration test:
#SpringBootTest
public class SecondIT {
public static GenericContainer postgreSQLContainer = new PostgreSQLContainer().
withReuse(true);
#BeforeAll
public static void beforeAll() {
postgreSQLContainer.start();
}
#Test
public void secondTest() {
}
}
There is currently a PR that adds documentation about this
I've put together a blog post explaining how to reuse containers with Testcontainers in detail.
If you decide go forward with the singleton pattern, mind the warning in "Database containers launched via JDBC URL scheme". I took hours till I note that, even though I was using the singleton pattern, an additional container was always being created mapped on a different port.
In summary, do not use the test containers JDBC (host-less) URIs, such as jdbc:tc:postgresql:<image-tag>:///<databasename>, if you need use the singleton pattern.
Accepted answer is great but the problem is you still have to repeat the configurations(creating, starting and etc.) for each integration tests. It would be better to have simpler configuration with fewer lines of code. I think cleaner version would be using JUnit 5 extensions.
This is how I solved the problem. Below sample uses MariaDB container but the concept is applicable to all.
Create the container config holding class:
public class AppMariaDBContainer extends MariaDBContainer<AppMariaDBContainer> {
private static final String IMAGE_VERSION = "mariadb:10.5";
private static final String DATABASE_NAME = "my-db";
private static final String USERNAME = "user";
private static final String PASSWORD = "strong-password";
public static AppMariaDBContainer container = new AppMariaDBContainer()
.withDatabaseName(DATABASE_NAME)
.withUsername(USERNAME)
.withPassword(PASSWORD);
public AppMariaDBContainer() {
super(IMAGE_VERSION);
}
}
Create an extension class that starts the container and sets the DataSource properties. And run migrations if needed:
public class DatabaseSetupExtension implements BeforeAllCallback {
#Override
public void beforeAll(ExtensionContext context) {
AppMariaDBContainer.container.start();
updateDataSourceProps(AppMariaDBContainer.container);
//migration logic here (if needed)
}
private void updateDataSourceProps(AppMariaDBContainer container) {
System.setProperty("spring.datasource.url", container.getJdbcUrl());
System.setProperty("spring.datasource.username", container.getUsername());
System.setProperty("spring.datasource.password", container.getPassword());
}
}
Add #ExtendWith to your test class
#SpringBootTest
#ExtendWith(MariaDBSetupExtension.class)
class ApplicationIntegrationTests {
#Test
void someTest() {
}
}
Another test
#SpringBootTest
#ExtendWith(MariaDBSetupExtension.class)
class AnotherIntegrationTests {
#Test
void anotherTest() {
}
}
Using either singleton containers or reusable containers are possible solutions but because they don't scope the life-cycle of the container to that of the application context both are less then ideal.
It is however possible to scope the container to the application contexts lifecycle by using a ContextCustomizerFactory and I've written about this in more detail in a blog post.
In a test use:
#Slf4j
#SpringBootTest
#EnabledPostgresTestContainer
class DemoApplicationTest {
#Test
void contextLoads() {
log.info("Hello world");
}
}
Then enable the annotation in META-INF/spring.factories:
org.springframework.test.context.ContextCustomizerFactory=\
com.logarithmicwhale.demo.EnablePostgresTestContainerContextCustomizerFactory
Which can be implemented as:
public class EnablePostgresTestContainerContextCustomizerFactory implements ContextCustomizerFactory {
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Inherited
public #interface EnabledPostgresTestContainer {
}
#Override
public ContextCustomizer createContextCustomizer(Class<?> testClass,
List<ContextConfigurationAttributes> configAttributes) {
if (!(AnnotatedElementUtils.hasAnnotation(testClass, EnabledPostgresTestContainer.class))) {
return null;
}
return new PostgresTestContainerContextCustomizer();
}
#EqualsAndHashCode // See ContextCustomizer java doc
private static class PostgresTestContainerContextCustomizer implements ContextCustomizer {
private static final DockerImageName image = DockerImageName
.parse("postgres")
.withTag("14.1");
#Override
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
var postgresContainer = new PostgreSQLContainer<>(image);
postgresContainer.start();
var properties = Map.<String, Object>of(
"spring.datasource.url", postgresContainer.getJdbcUrl(),
"spring.datasource.username", postgresContainer.getUsername(),
"spring.datasource.password", postgresContainer.getPassword(),
// Prevent any in memory db from replacing the data source
// See #AutoConfigureTestDatabase
"spring.test.database.replace", "NONE"
);
var propertySource = new MapPropertySource("PostgresContainer Test Properties", properties);
context.getEnvironment().getPropertySources().addFirst(propertySource);
}
}
}
I'm not sure how #Testcontainers works, but I suspect it might work per class.
Just make your singleton static as described in Singleton pattern
and get it in every test from your signleton holder, don't define it in every test class.

injecting Mocks through a chain of dependency classes using Mockito

Hi i have implemented a series of classes that use dagger 2 Injection to inject it dependencies for each class and i am trying to mock these to run my unit tests but it fails to initialise the dependencies found from the lower tier of classes that have dependencies.
This works fine in real enviornment but not for testing
I tried marking all the dependencies as either Spy or Mock but it only seems to inject the mocks on the first layer of my class that gets invoked. Below are three classes marked ExampleOne,Two,Three, followed by the test class.
ExampleOne has a method that calls another method from ExampleTwo, that then finally calls another from ExampleThree.
Only ExampleTwo gets the mock/spy injected fine but not ExampleThree.
public class ExampleOne{
#Inject
ExampleTwo exampleTwo;
//implementations below
public void doSomethingOne(){
exampleTwo.doSomethingTwo;
}
}
public class ExampleTwo{
#Inject
ExampleThree exampleThree
public void doSomethingTwo(){
exampleThree.doPrintHello();
}
}
public class ExampleThree{
public void doPrintHello(){
Log.d("Print","Hello")
}
}
Below is my test
#RunWith(MockitoJUnitRunner.class)
public class TestExamples(){
#InjectMocks
ExampleOne exampleOne
#Spy
ExampleTwo exampleTwo = new ExampleTwo();
#Spy
ExampleThree exampleThree = new ExampleThree();
#Test
void test(){
exampleOne.doSomethingOne();
//some testing code here
}
}
Practice explicit dependency principle either via constructor injection or method injection. Next, unit tests should be isolated. You should have no need to access implementation concerns in this case. Your classes are tightly coupled to implementation concerns and not abstractions which is a code smell.
public class ExampleOne {
ExampleTwo exampleTwo;
#Inject
public ExampleOne(ExampleTwo exampleTwo) {
this.exampleTwo = exampleTwo;
}
//implementations below
public void doSomethingOne(){
exampleTwo.doSomethingTwo();
}
}
public interface ExampleTwo {
void doSomethingTwo();
}
public class ConcreteExampleTwo implements ExampleTwo {
private ExampleThree exampleThree;
#Inject
public ConcreteExampleTwo(ExampleThree exampleThree) {
this.exampleThree = exampleThree;
}
public void doSomethingTwo(){
exampleThree.doPrintHello();
}
}
public interface ExampleThree {
void doPrintHello();
}
//...code removed for brevity
ExampleOne has one dependency at that level and if that dependencies are not able to be mocked/stubbed/faked without side effects then there is a problem with the design of the target class.
#RunWith(MockitoJUnitRunner.class)
public class TestExamples(){
#Mock
ExampleTwo exampleTwo;
#InjectMocks
ExampleOne exampleOne
#Test
void test(){
exampleOne.doSomethingOne();
verify(exampleTwo).doSomethingTwo();
}
}
With the above suggested changes ExampleOne can be tested in isolation without any knock on effects.
The concrete implementation of ExampleTwo can also be tested in isolation as well.

Dagger 2.11 - Injecting different networkAPI implementations in acceptance tests

I have a simple app. It uses a network API (Volley). It uses Dagger 2.11 (using AndroidInjector) for dependency inversion. The NetworkAPI is injected in the MainActivity. For the acceptance tests I use my own TestRunner, extended from AndroidJUnitRunner.
To fake the real Network API, I use an ImmediateResponseNetwork object. This 'network' responses immediately. The instance is provided by a TestNetworkApiModule and declared in the module list of the TestAppComponent. See parts of the source code below.
At the times, before I used Dagger, I used the ImmediateResponseNetwork to define different responses of the networkRequest, dependend on the test. Which seem not be possible now, because the network is hidden in the activity under test. And after creation of the network I can't access it from the outside to prepare it.
I also can't test a slower network connection. That is why I would like to at least to inject another fake slow-response-network object and I would like to have the ability to prepare the response via ImmediateResponseNetwork.
How can I do this?
An example test I would like to write is:
Testing, that the loading indicator is displayed, while an network request is running.
I have no idea how to implement this now. It looks like, that DI is in the way for easier testing, instead of the other way around.
I guess, there is something missing in my thinking.
The source code on which the question is based upon: https://github.com/Minsky/SO_Question_AndroidInjectionInTestsWithDagger
Sample Test, I want to do:
#Rule
public ActivityTestRule<MainActivity> mainActivityTestRule = new ActivityTestRule<>(MainActivity.class, true, false);
public void afterStartLoadingPleaseWaitInfoIsDisplayed() throws Exception {
MainActivityTestRule.launchActivity(new Intent());
onView(withId(R.id.activity_loading_indicator)).check(matches(isDisplayed()));
}
My relevant test setup classes:
#Module
public class TestNetworkApiModule extends NetworkApiModule {
#Provides
static NetworkApi provideNetworkApi(Context context) {
return new ImmediateResponseNetwork();
}
}
#Singleton
#Component(modules = {
AppModule.class,
TestNetworkApiModule.class,
ActivityBindingModule.class,
AndroidSupportInjectionModule.class
})
public interface TestAppComponent extends AppComponent {
void inject(TestMyApplication app);
#Override
void inject(DaggerApplication instance);
#Component.Builder
interface Builder {
#BindsInstance
TestAppComponent.Builder application(Application application);
TestAppComponent build();
}
}
public class TestMyApplication extends DaggerApplication {
#Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
TestAppComponent appComponent = DaggerTestAppComponent.builder().application(this).build();
appComponent.inject(this);
return appComponent;
}
}
The activity where the networkAPI is injected:
public class MainActivity extends AppCompatActivity {
private TextView responseView;
private boolean progressBarVisible;
#Inject
NetworkApi networkApi;
...
}

Use Guice to create components to use with ThreadWeaver

The application I have been working on has been getting more and more complicated, and it's gotten to the point where I have been running into the same problems over and over again with concurrency. It no longer made any sense to solve the same problems and not have any regression tests.
That's when I found ThreadWeaver. It was really nice for some simple concurrency cases I cooked up, but I started to get frustrated when trying to do some more complicated cases with my production code. Specifically, when injecting components using Guice.
I've had a bit of a hard time understanding the implications of the way ThreadWeaver runs tests, and looked for any mention of Guice or DI in the wiki documents, but with no luck.
Is Guice compatible with ThreadWeaver?
Here is my test
#Test
public void concurrency_test() {
AnnotatedTestRunner runner = new AnnotatedTestRunner();
runner.runTests(OPYLWeaverImpl.class, OPYLSurrogateTranscodingService.class);
}
Here is my test implementation
public class OPYLWeaverImpl extends WeaverFixtureBase {
#Inject private TaskExecutor taskExecutor;
#Inject private Serializer serializer;
#Inject private CountingObjectFileMarshaller liveFileMarshaller;
#Inject private GraphModel graphModel;
#Inject private CountingModelUpdaterService updaterService;
#Inject private BabelCompiler babelCompiler;
#Inject private EventBus eventBus;
OPYLSurrogateTranscodingService service;
private Path testPath;
#ThreadedBefore
public void before() {
service = new OPYLSurrogateTranscodingService(eventBus, taskExecutor, serializer, liveFileMarshaller,
() -> new OPYLSurrogateTranscodingService.Importer(graphModel, babelCompiler, updaterService, eventBus),
() -> new OPYLSurrogateTranscodingService.Validator(eventBus, babelCompiler),
() -> new OPYLSurrogateTranscodingService.Exporter(graphModel, updaterService));
}
#ThreadedMain
public void mainThread() {
testPath = FilePathOf.OASIS.resolve("Samples/fake-powershell-unit-test.opyl");
service.applyToExistingGraphModel(testPath);
}
#ThreadedSecondary
public void secondaryThread() {
}
#ThreadedAfter
public void after() {
}
And the WeaverFixtureBase
public class WeaverFixtureBase {
#Inject protected CountingEventBus eventBus;
#Before public final void setupComponents() {
Injector injector = Guice.createInjector(new WeaverTestingEnvironmentModule(CommonSerializationBootstrapper.class));
injector.getMembersInjector((Class) this.getClass()).injectMembers(this);
}
private class WeaverTestingEnvironmentModule extends AbstractModule {
private final Class<? extends SerializationBootstrapper> serializationBootstrapper;
public WeaverTestingEnvironmentModule(Class<? extends SerializationBootstrapper> serializationConfiguration) {
serializationBootstrapper = serializationConfiguration;
}
#Override protected void configure() {
bind(TaskExecutor.class).to(FakeSerialTaskExecutor.class);
bind(SerializationBootstrapper.class).to(serializationBootstrapper);
bind(ModelUpdaterService.class).toInstance(new CountingModelUpdaterService());
bindFactory(StaticSerializationConfiguration.Factory.class);
CountingEventBus localEventBus = new CountingEventBus();
bind(Key.get(EventBus.class, Bindings.GlobalEventBus.class)).toInstance(localEventBus);
bind(Key.get(EventBus.class, Bindings.LocalEventBus.class)).toInstance(localEventBus);
bind(CountingEventBus.class).toInstance(localEventBus);
bind(EventBus.class).toInstance(localEventBus);
}
#Provides
#Singleton
public GraphModel getGraphModel(EventBus eventBus, Serializer serializer) {
return MockitoUtilities.createMockAsInterceptorTo(new GraphModel(eventBus, serializer));
}
}
But when the classloader loads OPYLWeaverImpl, none of the Guice stuff goes off and I get a big pile of nulls.
I feel like this is one of those "missing-something-really-simple" kind of scenarios. Sorry if it is!
The above comment is right. Thread-weaver is fully agnostic of JUnit. Thread weaver is its own runner that executes a test case respecting its own annotations. You must not use any JUnit-specific annotation within a Thread Weaver test.
Other than that, Thread Weaver does not need any compatibility for a specific framework. It manipulates Java byte code and loads that manipulated code using aeperate class loaders.
Finally, a Thread Weaver test without any secondary test does not make any sense. Thread weaver works by interleaving seperate execution paths. Without a second thread, Thread Weaver only steps through a single thread without adding any value.

Robolectric custom TestRunner not working when started from Gradle

I wanted to implement a custom Application class Shadow, to override a getInstance() method in it. I am using Robolectric 3.0 and have created a MyRobolectricTestRunner class, overriding the createClassLoaderConfig() method like this:
public class MyRobolectricTestRunner extends RobolectricTestRunner {
public MyRobolectricTestRunner(Class<?> testClass) throws InitializationError {
super(testClass);
}
#Override
public InstrumentationConfiguration createClassLoaderConfig() {
InstrumentationConfiguration.Builder builder = InstrumentationConfiguration.newBuilder();
builder.addInstrumentedClass(App.class.getName());
return builder.build();
}
}
The ShadowApp class looks like this:
#Implements(App.class)
public class ShadowApp{
#RealObject private static App instance;
public static void setAppInstance(App app){
instance = app;
}
#Implementation
public static App getInstance(){
return instance;
}
}
And the test which uses the Runner is annotated like this:
#RunWith(MyRobolectricTestRunner.class)
#Config(manifest=Config.NONE, shadows = {ShadowApp.class}, constants = BuildConfig.class, sdk = 21)
public class SomeShadowTest {
Now the problem is that when I run the test manually (hitting "Run..." for this single test class only), it passes without a problem, but when I use the Gradle "testDebug" task, the test fails as if the Shadow class was not used at all :(
I have tried changing the Runner parent class to RobolectricGradleTestRunner, but ended up in a dead end when it forced me to make the ShadowApp class extend a ShadowApplication class, which has getInstance() method as well... :(
Any tips on how to solve this issue?
I suggest you do not create shadow for application but instead use TestApplication class which Robolectric uses as test variant of the application class.
For this you just need to create class which extends your application class and has name Test and is placed in the root of your project - package of class same as package name of project.
See example below:
Assume, you package name is com.example.robolectric
// src/main/java/com/example/robolectric
public class YourAplication extends Application {
...
}
// src/test/java/com/example/robolectric
/**
* Robolectric uses class with name Test<ApplicationClassName> as test variant of the application
* class. We use test application for API class injection so we need test version of this class.
*/
public class TestYourAplication extends YourAplication {
...
}

Categories