I have a simple HelloWorld Activity that I try to test with an Android JUnit test. The application itself runs like it should but the test fails with an
"java.lang.RuntimeException: Unable to resolve activity for: Intent { action=android.intent.action.MAIN flags=0x10000000 comp={no.helloworld.HelloWorld/no.helloworld.HelloWorld} }
at no.helloworld.test.HelloWorldTestcase.setUp(HelloWorldTestcase.java:21)"
This is my activity class:
package no.helloworld;
import android.app.Activity; import
android.os.Bundle;
public class HelloWorld extends
Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
} }
And the test:
public class HelloWorldTestcase extends ActivityInstrumentationTestCase2 {
private HelloWorld myActivity;
private TextView mView;
private String resourceString;
public HelloWorldTestcase() {
super("no.helloworld.HelloWorld", HelloWorld.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
myActivity = this.getActivity();
mView = (TextView) myActivity.findViewById(no.helloworld.R.id.txt1);
resourceString = myActivity
.getString(no.helloworld.R.string.helloworld);
}
public void testPreconditions() {
assertNotNull(mView);
}
public void testText() {
assertEquals(resourceString, (String) mView.getText());
}
protected void tearDown() throws Exception {
super.tearDown();
}
Why does the test fail? The activity is (of course) defined in AndroidManifest.xml and the application runs as it should.
The package in the constructor call should match the instrumentation target in the manifest. It should be "no.helloworld" instead of "no.helloworld.HelloWorld"
Related
With the latest Dagger2 we can inject dependencies through the following code:
public class BaseActivity extends LifecycleActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}
}
Other activities that require DI inherit from this BaseClass.
For my instrumentation tests, I don't want to use Dagger, I can just mock the objects.
My setup for the instrumentation test (I'm currently testing LoginActivity, which extends BaseActivity) is not special and as follows:
TestRunner:
public class LivefeedTestRunner extends AndroidJUnitRunner{
#Override
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return super.newApplication(cl, TestApp.class.getName(), context);
}
}
TestApp:
public class TestApp extends Application {
#Override
public void onCreate() {
super.onCreate();
}
}
The problem is that running the instrumentation test results in an error caused by:
Caused by: java.lang.RuntimeException: com.example.kimgysen.livefeed_v002.TestApp does not implement dagger.android.HasActivityInjector
at dagger.android.AndroidInjection.inject(AndroidInjection.java:48)
at com.example.kimgysen.livefeed_v002.ui.BaseActivity.onCreate(BaseActivity.java:12)
at com.example.kimgysen.livefeed_v002.ui.login.LoginActivity.onCreate(LoginActivity.java:32)
at android.app.Activity.performCreate(Activity.java:6237)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
at android.support.test.runner.MonitoringInstrumentation.callActivityOnCreate(MonitoringInstrumentation.java:624)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
... 9 more
Which points to the following line:
public class BaseActivity extends LifecycleActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this); // <-- this line
super.onCreate(savedInstanceState);
}
}
Any idea how I can easily bypass this?
In my app itself, I implement dagger.android.HasActivityInjector, but I don't need it for my instrumentation test.
I solved the problem by creating a fake activityInjector as suggested in the following post:
https://github.com/google/dagger/blob/master/javatests/dagger/android/AndroidInjectionTest.java#L60
(equivalent for fakeActivityInjector)
public class TestApp extends Application implements HasActivityInjector {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public AndroidInjector<Activity> activityInjector() {
return fakeActivityInjector("injected by app");
}
public static class InjectableActivity extends Activity {
String tag;
}
private static AndroidInjector<Activity> fakeActivityInjector(String tag) {
return instance -> {
if (instance instanceof InjectableActivity) {
((InjectableActivity) instance).tag = tag;
}
};
}
}
There is an alternative solution in the android-architecture-components samples on Github.
They inject the activities trough ActivityLifecycleCallbacks. For instrumented tests they use a TestApp that does not register ActivityLifecycleCallbacks so it injects nothing.
See https://stackoverflow.com/a/48101811/1552622.
I am developing a test class for my application. The test class code looks like this:
public class ProfileActivityTest extends ActivityInstrumentationTestCase2<ProfileActivity> {
ProfileActivity profileActivity;
#SuppressLint("NewApi")
public ProfileActivityTest(Class<ProfileActivity> activityClass) {
super(activityClass);
// TODO Auto-generated constructor stub
}
#SuppressLint("NewApi")
public ProfileActivityTest() {
super(ProfileActivity.class);
}
protected void setup() throws Exception {
super.setUp();
profileActivity = getActivity();
}
public void test_profileActivityLoggingIn() {
assertNotNull(profileActivity);
assertEquals(View.GONE, profileActivity.findViewById(R.id.btnAddOrEdit).getVisibility());
}
protected void tearDown() throws Exception {
super.tearDown();
}
}
The problem is that I get assertionFailure on assertNotNull(profileActivity) though profileActivity is instantiated in setup(). I don't understand what I am doing wrong;
As #njzk2 has mentioned, "setup" should be changed to "setUp".
My app has only one activity and based on many fragments. How I can test this fragment in a right way? Give me an example, please.
Cause I try this test class:
#LargeTest
public class ActivityTest extends ActivityInstrumentationTestCase2<ActivityEx> {
public ActivityTest() {
super(ActivityEx.class);
}
public void setUp() throws Exception {
super.setUp();
getActivity();
}
public void testTest() {
//simple example
assertEquals(true, true);
}
}
And in result I've failed due to ClassCastException.
Rather do it like this:
public class ActivityTest extends android.test.ActivityInstrumentationTestCase2
{
public ActivityTest()
{
super(ActivityEx.class);
}
#Override
protected void setUp() throws Exception
{
super.setUp();
getActivity();
}
public void testTest() {
//simple example
assertEquals(true, true);
}
}
If you interested I also posted a tutorial on testing fragments http://www.stevenmarkford.com/testing-fragments-with-android-espresso-basic-example/
I run the tests in Android Studio, running task - "test". My test failed, my html report detailed:
junit.framework.AssertionFailedError: Class Test has no public constructor TestCase(String name) or TestCase()
at junit.framework.Assert.fail(Assert.java:57)
at junit.framework.TestCase.fail(TestCase.java:227)
at junit.framework.TestSuite$1.runTest(TestSuite.java:100)
at junit.framework.TestCase.runBare(TestCase.java:141)
at junit.framework.TestResult$1.protect(TestResult.java:122)
at junit.framework.TestResult.runProtected(TestResult.java:142)
at junit.framework.TestResult.run(TestResult.java:125)
at junit.framework.TestCase.run(TestCase.java:129)
at junit.framework.TestSuite.runTest(TestSuite.java:255)
at junit.framework.TestSuite.run(TestSuite.java:250)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:84)
My source file:
#LargeTest
public class Test extends ActivityInstrumentationTestCase2<MainActivity>{
public Test(Class <MainActivity> activityClass) {
super(activityClass);
}
#Override
public void setUp() throws Exception {
super.setUp();
getActivity();
}
public void testCheck(){
onView(withId(R.id.text))
.check(matches(withText("Hello world!")));
}
}
The problem is exactly what the error message says it is: You did not provide a parameter-free constructor.
Add this constructor to your test class:
public Test() {
super(MainActivity.class);
}
The prototype of a test class with espresso should be:
public class MainTest extends
ActivityInstrumentationTestCase2<MainActivity>{
public MainTest() {
super(MainActivity.class);
}
#Override
public void setUp(){
getActivity();
}
#Override
public void tearDown(){
}
public void test1(){
}
public void test2(){
}
}
I have an activity A that launch an activity B.
I'd like to have a robotium project to test my app so I'v created a first test class for activity A and all goes well.
I'd like now to create another test class for testing Activity B but it require some init from activity A.
I tried this:
BTestClass extends ActivityInstrumentationTestCase2 {
private Solo solo;
private ATestClass testA;
#Override
protected void setUp() throws Exception {
Log.i(TAG, "setUp");
solo = new Solo(getInstrumentation(), getActivity());
testA = new ATestClass();
testA.setUp();
testA.testAddAccount();
solo.clickInList(0);
}
[… more test method]
}
I got a NullPointerException when testA is doing getActivity()
I do it this way:
public class BTest extends ActivityInstrumentationTestCase2<SplashScreenActivity> {
protected static final String TARGET_PACKAGE_ID = "app.under.test";
protected Solo solo;
public BTest() {
super(TARGET_PACKAGE_ID, StartingActivity.class);
}
#Override
public void setUp() throws Exception {
super.setUp();
solo = new Solo(getInstrumentation(), getActivity());
// setup stuff
}
#Override
public void tearDown() throws Exception {
// teardown stuff
super.tearDown();
}
}
All testcases just inherit from BTest then
public class OneTest extends BTest {
public void test_OneTest() {
//test stuff
solo.clickOnButton("Ok");
}
}