Testing with Robolectric in Eclipse

2019-07-16 04:09发布

问题:

I am trying to run a simple test with Robolectric in eclipse. I followed this tutorial, but got this error :

java.lang.RuntimeException: java.io.FileNotFoundException: C:\Vishal\Development\workspace>\AndroidHelloWorldTester.\AndroidManifest.xml not found or not a file; it >should point to your project's AndroidManifest.xml

Then as per Eugen's advice at here, I tried to extend the RobolectricTestRunner class as per instructed here but got this error :- (well I couldn't write the constructor exactly as directed since it was causing compilation error)

java.lang.Exception: Test class should have exactly one public zero-argument constructor

Currently this is the class :-

package com.myTest;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.model.InitializationError;

import android.widget.Button;
import android.widget.TextView;

import com.visd.helloworld.AndroidHelloWorldActivity;
import com.visd.helloworld.R;
import com.xtremelabs.robolectric.RobolectricTestRunner;

@RunWith(RobolectricTestRunner.class)
public class Ahtest extends RobolectricTestRunner {

    public Ahtest(Class AndroidHelloWorldActivity) throws InitializationError {
    super(AndroidHelloWorldActivity, "<the project root location>");
    // TODO Auto-generated constructor stub
}

    private Button pressMeButton;
    private TextView results;
    AndroidHelloWorldActivity activity;
    @Before
    public void setUp() throws Exception {
        activity = new AndroidHelloWorldActivity();

        activity.onCreate(null);
        pressMeButton = (Button) activity.findViewById(R.id.mybut1);
        results = (TextView) activity.findViewById(R.id.text1);
    }

    @After
    public void tearDown() throws Exception {
    }

    @Test
    public void testSomethingMeaningfulToMyApp() {
         pressMeButton.performClick();
         String resultsText = results.getText().toString();
         assertThat(resultsText, equalTo("Button Clicked"));
    }

}

P.N. :
1) I made different project for the application and for the test.
2) I could not write the constructor exactly as specified since if I specified :-

super(testClass, new File("../other/project-root"));

I would get compilation error. Please help.

回答1:

Vishal,

you're mixing test and runner classes.

junit works in general like:

for (TestClass c: allTests) {
    Test t = TestClass.newInstance();

    testListener.startTest(t.getName());
    try {
       t.beforeTest();
       t.run();
       t.afterTest();

       testListener.testPass(t.getName());
    } catch (Exception e) {
       if (t.isExpectedException(e)) {
           testListener.testPass(t.getName());
       } else if (isAssertException(e)) {
           testListener.testFail(t.getName(), getExplanation(e));
       } else {
           testListener.testError(t.getName(), e);
       }
    }

    testListener.testEnd(t.getName());
}

Because of Class.newInstance() method call it's required to have public non-zero parameters constructor for test class. Annotations @Test, @Before and @After mark to junit which classes are test classes.

The code above is kind of test runner class. Sometimes you need additional logic from test runner class. For example Robolectric and PowerMock are replacing standard ClassLoader with own specific for purposes. Robolectric to provide own implementation for Android classes. PowerMock for ability to mock static, final classes and methods, as well for mocking classes constructors.

@RunWith annotation exists to notify junit that it should use another test runner for test class. So Robolectric Android test should have @RunWith(RobolectricTestRunner.class). However you have ability to add additional functionality to Robolectric test runner by extending RobolectricTestRunner class. For example for own shadowing or pointing to specific AndroidManifest.xml file.

So you should have your own test runner class AHTesRunner where you will point Robolectric to specific manifest file location:

public class AHTestRunner extends RobolectricTestRunner {}

And you need to notify junit that it should use your own test runner (customized Robolectric test runner):

@RunWith(AHTestRunner.class)
public class AHTest {
    @Before
    ......
    @Test
    ......
    @After
}

Hope this is much clear now