javaandroidrobolectricandroid-cardview

How to test an activity with robolectric while it has android.support.v7.widget.CardView?


I have complex project that contains few flavors and project dependency projects. If you consider MY_PROJECT is the project, it contains PROJECT_1 as main project, PROJECT_2 and PROJECT_3 are acting as dependency for PROJECT_1. I've put my tests under PROJECT_2/src/test/java.

I'm trying to write few simple methods to test my splash screen based on.

This is the code I have written:

package com.something.splash;

import android.os.Build;
import android.view.View;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import com.FLAVOUR_1.BuildConfig;
import com.FLAVOUR_1.R;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.KITKAT, manifest = "../PROJECT_1/src/main/AndroidManifest.xml")
public class SplashActivityTest
{
    private SplashActivity mSplashActivity;

    @Test
    public void testMe() {
        assertTrue(1 > 0);
    }

    @Before
    public void setup()  {
        this.mSplashActivity = Robolectric.buildActivity(SplashActivity.class).create().get();  <==== PROBLEM
    }

    @Test
    public void checkActivityNotNull() throws Exception {
        assertNotNull("How come SplashActivity is null???", this.mSplashActivity);
    }

    @Test
    public void checkVisibilityOfCardView() throws Exception {
        View ivBranding = this.mSplashActivity.findViewById(R.id.ivBranding);
        Assert.assertEquals(ivBranding.getVisibility(), View.VISIBLE);

        View cardView = this.mSplashActivity.findViewById(R.id.splash_error_layout);
        assertNull("CardView MUST be invisible by default.", cardView);
    }
}

This is the output when I run ./gradlew test command:

com.SOMETHING.splash.SplashActivityTest > checkActivityNotNull FAILED
    android.view.InflateException at SplashActivityTest.java:34 (MARKED WITH <=== ABOVE)
        Caused by: java.lang.reflect.InvocationTargetException at SplashActivityTest.java:34
            Caused by: java.lang.NoClassDefFoundError at SplashActivityTest.java:34
                Caused by: java.lang.ClassNotFoundException at SplashActivityTest.java:34

com.SOMETHING.splash.SplashActivityTest > testMe FAILED
    android.view.InflateException at SplashActivityTest.java:34
        Caused by: java.lang.reflect.InvocationTargetException at SplashActivityTest.java:34
            Caused by: java.lang.NoClassDefFoundError at SplashActivityTest.java:34

com.SOMETHING.splash.SplashActivityTest > checkVisibilityOfCardView FAILED
    android.view.InflateException at SplashActivityTest.java:34
        Caused by: java.lang.reflect.InvocationTargetException at SplashActivityTest.java:34
            Caused by: java.lang.NoClassDefFoundError at SplashActivityTest.java:34

3 tests completed, 3 failed
:PROJECT_2:testDebug FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':PROJECT_2:testDebug'.
> There were failing tests. See the report at: file:///Users/admin/Desktop/android/MY_FOLDER/PROJECT_2/build/reports/tests/debug/index.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 14.546 secs

and finally index.html shows these details:

    android.view.InflateException: XML file build/intermediates/res/debug/layout/activity_splash.xml line #-1 (sorry, not yet implemented): Error inflating class android.support.v7.widget.CardView
        at android.view.LayoutInflater.createView(LayoutInflater.java:620)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:696)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
    .
    .
    .
Caused by: java.lang.ClassNotFoundException: android.support.v7.cardview.R$styleable
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    .
    .
    .

Sorry for long explanation but I guess it was mandatory. I spent a day and still couldn't figure it out what is the problem and why this f.cardView cannot be recognized while application works fine when I build the project. Any idea would be appreciated. Thanks.

I have these lines in my PROJECT_2 gradle file:

apply plugin: 'com.android.library'
android androidConfiguration

android {
    sourceSets {
        main {
            res.srcDirs = ['src/main/res', 'src/main/res-flags']
        }
    }
}

dependencies {        
    ...
    compile 'com.android.support:recyclerview-v7:22.1.1'
    compile 'com.android.support:cardview-v7:22.1.1'
    compile 'com.google.android.gms:play-services-gcm:7.3.0'
    compile 'com.google.android.gms:play-services-maps:7.3.0'

    // Roboelectric testing
    testCompile 'junit:junit:4.12'
    testCompile 'org.robolectric:robolectric:3.0-rc3'
}

Solution

  • Okay, a thing that I learnt from one of my bosses is "When you are working on a very big project and face a bug/problem/issue that you cannot fix it (easily), try to create a new project in order to replicate the issue and fix it over there first". Having this experience in my mind, I created a new project and tried to replicate the issue. However, I'm happy to say that, it's working fine. Then I just to compare and fix my main project.

    For those how have same problem, I have pushed my sample project at this repo: https://github.com/Hesamedin/RobolectricTester/tree/master/app/src/test


    Update

    I found that there is no problem when I have a project and a flavor. However, problem occurs when I have flavors. Following pages helped me in order to fix my issue. Please have a look at these pages (second one particularly):