I'm having an error message below and looked around but there is a solution for service and tried to get it right.
How to test an IntentService with Robolectric?
java.lang.RuntimeException: java.lang.NoSuchMethodException:
tapme.data.service.AlarmService.(java.lang.String)
Here is the unit test that I implemented -
#RunWith(RobolectricTestRunner.class)
public class AlarmServiceUnitTest {
private AlarmService service;
private IntentServiceController<AlarmService> controller;
#Before
public void setup() {
controller = Robolectric.buildIntentService(AlarmService.class).create();
service = controller.create().get();
}
#Test
public void alarmServiceShouldBeNotNull() {
assertNotNull(service);
}
}
Related
I have a util method which will go some actiivty by routing.
// RoutingUtil.java
public static void goRouting(Context context, String routing);
And I want test this method.
So I did something like this
#RunWith(AndroidJUnit4.class)
#HiltAndroidTest
public class RoutingUiUtilsTest {
#Rule
public HiltAndroidRule hiltRule = new HiltAndroidRule(this);
#Before
public void setUp() {
hiltRule.inject();
}
#Test
public void testSmartGo() {
ActivityScenario.launch(MainActivity.class);
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
RoutingUtil.goRouting(context, "", "schema://a_activity_path");
}
}
The dest Activity is AActivity which used the hilt by annoutation #AndroidEntryPoint
#AndroidEntryPoint
class AActivity extends Activity {
}
Then I run test in terminal
./gradlew connectedAndroidTest
And error throws
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.somepackage/com.somepackage.AActivity}:
java.lang.IllegalStateException: The component was not created. Check
that you have added the HiltAndroidRule
I think the reason is I didn't start AActivity by hilt test componet, like ActivityScenario.launch(AActivity.class);, but what I want test is RoutingUtil.goRouting so I can't use hilt test component.
So how to test RoutingUtil.goRouting?
#Before class does not start the activity. For this reason, no views to do actions on are available. Is it possible to have the activity started before #BeforeClass
An exemplary test that fails due to this:
#RunWith(AndroidJUnit4.class)
public class MakeFeedingTest {
#Rule
public ActivityScenarioRule<MainActivity> scenarioRule = new ActivityScenarioRule<>(MainActivity.class);
#BeforeClass
public static void setup() {
onView(withId(R.id.add)).perform(click());
onView(withId(R.id.save)).perform(click());
}
#Test
public void superBasicTest() {
onView(withId(R.id.new_element)).check(matches(isDisplayed()));
}
}
How can I make the activity start before #BeforeClass is executed, so that the test does not fail anymore?
Usecase: Add an element to a list before the other tests are exectued.
That is not relevant design pattern here, and I wouldnt do it in that way.
For this to work, do something like this:
#RunWith(AndroidJUnit4.class)
public class MakeFeedingTest {
#Rule
public ActivityScenarioRule<MainActivity> scenarioRule = new ActivityScenarioRule<>(MainActivity.class);
#BeforeClass
public static void setup() {
}
#Test
public void superBasicTest() {
clickButtons()
onView(withId(R.id.new_element)).check(matches(isDisplayed()));
}
private void clickButtons() {
onView(withId(R.id.add)).perform(click());
onView(withId(R.id.save)).perform(click());
}
}
If you're insisting on using it in this way, add aditional parameters to the screnario rule as following and see if that will work:
#Rule
public ActivityScenarioRule<MainActivity> scenarioRule = ActivityTestRule(MainActivity.class.java, true, true)
I am running my login unit tests which keep returning errors :
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
ObservableJust cannot be returned by doServerLoginApiCall()
doServerLoginApiCall() should return Single
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
I am not sure why that throws, even when I cross checked everything is correct even though tests keep failing due to the above reason. Here's my code:
LoginPresenterTest:
#RunWith(MockitoJUnitRunner.class)
public class LoginPresenterTest {
#Mock
LoginMvpView mMockLoginMvpView;
#Mock
DataManager mMockDataManager;
private LoginPresenter<LoginMvpView> mLoginPresenter;
private TestScheduler mTestScheduler;
#BeforeClass
public static void onlyOnce() throws Exception {
}
#Before
public void setUp() throws Exception {
CompositeDisposable compositeDisposable = new CompositeDisposable();
mTestScheduler = new TestScheduler();
TestSchedulerProvider testSchedulerProvider = new TestSchedulerProvider(mTestScheduler);
mLoginPresenter = new LoginPresenter<>(
mMockDataManager,
testSchedulerProvider,
compositeDisposable);
mLoginPresenter.onAttach(mMockLoginMvpView);
}
#Test
public void testServerLoginSuccess() {
String email = "dummy#gmail.com";
String password = "password";
LoginResponse loginResponse = new LoginResponse();
doReturn(Observable.just(loginResponse))
.when(mMockDataManager)
.doServerLoginApiCall(new LoginRequest
.ServerLoginRequest(email, password));
mLoginPresenter.onServerLoginClick(email, password);
mTestScheduler.triggerActions();
verify(mMockLoginMvpView).showLoading();
verify(mMockLoginMvpView).hideLoading();
verify(mMockLoginMvpView).openMainActivity();
}
#After
public void tearDown() throws Exception {
mLoginPresenter.onDetach();
}
Here is my testscheduleprovider :
public class TestSchedulerProvider implements SchedulerProvider {
private final TestScheduler mTestScheduler;
public TestSchedulerProvider(TestScheduler testScheduler) {
this.mTestScheduler = testScheduler;
}
#Override
public Scheduler ui() {
return mTestScheduler;
}
#Override
public Scheduler computation() {
return mTestScheduler;
}
#Override
public Scheduler io() {
return mTestScheduler;
}
}
The error is thrown at LoginPresentertest at the line
.doServerLoginApiCall(new LoginRequest
.ServerLoginRequest(email, password));
Any idea how I can alter this to work?
Thanks!
Apparently your doServerLoginApiCall returns single, but you're trying to mock it with Observable.just(loginResponse). It should be something like Single.just(loginResponse)
I'm trying to setup and instrumental unit test for Activity with FirebaseAuth. When I run the application, everything works just fine. The problem is within the setup of instrumental unit tests.
Activity:
public final class GoogleSignInActivity extends AppCompatActivity{
#Override
protected void onCreate(final Bundle savedInstanceState) {
...
if (FirebaseApp.getApps(this).isEmpty()) {
FirebaseApp.initializeApp(this);
}
mFirebaseAuth = FirebaseAuth.getInstance();
}
}
Test:
#RunWith(AndroidJUnit4.class)
public class GoogleSignInActivityIntegrationTest extends UiTestPrerequesites {
#Rule
public final ActivityTestRule<GoogleSignInActivity> mActivityRule = new ActivityTestRule<>(
GoogleSignInActivity.class, false, true);
#Before
public void setup(){
if (FirebaseApp.getApps(InstrumentationRegistry.getContext()).isEmpty()) {
FirebaseApp.initializeApp(InstrumentationRegistry.getContext());
}
}
#Test
#SmallTest
public void implements_GoogleSignInWorkerFragment_GoogleSignInUiChangesListener() {
//FirebaseApp.initializeApp(InstrumentationRegistry.getContext()); (this doesn't help)
assertThat(mActivityRule .getActivity(),
notNullValue());
}
}
Exception (only when running test, not app):
Caused by: java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process com.twofortyfouram.ui.test. Make sure to call FirebaseApp.initializeApp(Context) first.
I think your issue with applicationID ( a.k.a package name ). you should add your application Id for testing to Firebase project account as well.
it has suffix: test
In general it looks like:
[ApplicationID].test
i.e.
com.apipas.android.hello.test
release applicationId is
com.apipas.android.hello
I hope that may help you,'.
I’m trying to test an Activity with Mockito & Dagger. I have been able to inject dependencies to Activity in my application but when testing the Activity, I have not been able to inject mock to the Activity. Should I inject Activity to test or let getActivity() create it?
public class MainActivityTest extends
ActivityInstrumentationTestCase2<MainActivity> {
#Inject Engine engineMock;
private MainActivity mActivity;
private Button mLogoutBtn;
public MainActivityTest() {
super(MainActivity.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
// Inject engineMock to test
ObjectGraph.create(new TestModule()).inject(this);
}
#Override
protected void tearDown() {
if (mActivity != null)
mActivity.finish();
}
#Module(
includes = MainModule.class,
entryPoints = MainActivityTest.class,
overrides = true
)
static class TestModule {
#Provides
#Singleton
Engine provideEngine() {
return mock(Engine.class);
}
}
#UiThreadTest
public void testLogoutButton() {
when(engineMock.isLoggedIn()).thenReturn(true);
mActivity = getActivity();
mLogoutBtn = (Button) mActivity.findViewById(R.id.logoutButton);
// how to inject engineMock to Activity under test?
ObjectGraph.create(new TestModule()).inject(this.mActivity);
assertTrue(mLogoutBtn.isEnabled() == true);
}
}
I use Mockito and Dagger for functional testing.
The key concept is that your test class inherits from ActivityUnitTestCase, instead of ActivityInstrumentationTestCase2; the latter super-class call onStart() life-cycle method of Activity blocking you for inject your test doubles dependencies, but with first super-class you can handle the life-cycle more fine-grained.
You can see my working examples using dagger-1.0.0 and mockito for test Activities and Fragments in:
https://github.com/IIIRepublica/android-civicrm-test
The project under test is in:
https://github.com/IIIRepublica/android-civicrm
Hope this helps you
I did some more experimenting and found out that Dagger is not able to create activity correctly when it is injected to test. In the new version of test, testDoSomethingCalledOnEngine passes but onCreate is not called on the MainActivity. The second test, testDoSomethingUI fails and there are actually two instances of MainActivity, onCreate gets called to the other instance (created by ActivityInstrumentationTestCase2 I quess) but not to the other. Maybe the developers at Square only thought about testing Activites with Robolectric instead of Android instrumentation test?
public class MainActivityTest extends
ActivityInstrumentationTestCase2<MainActivity> {
#Inject Engine engineMock;
#Inject MainActivity mActivity;
public MainActivityTest() {
super(MainActivity.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
// Inject engineMock to test & Activity under test
ObjectGraph.create(new TestModule()).inject(this);
}
#Module(
includes = MainModule.class,
entryPoints = MainActivityTest.class,
overrides = true
)
static class TestModule {
#Provides
#Singleton
Engine provideEngine() {
return mock(Engine.class);
}
}
public void testDoSomethingCalledOnEngine() {
when(engineMock.isLoggedIn()).thenReturn(true);
mActivity.onSomethingHappened();
verify(engineMock).doSomething();
}
#UiThreadTest
public void testDoSomethingUI() {
when(engineMock.isLoggedIn()).thenReturn(true);
mActivity.onSomethingHappened();
Button btn = (Button) mActivity.findViewById(R.id.logoutButton);
String btnText = btn.getText().toString();
assertTrue(btnText.equals("Log out"));
}
}
I have put everything together and made demo app that shows how to test with dagger: https://github.com/vovkab/dagger-unit-test
Here is my pervious answer with more details:
https://stackoverflow.com/a/24393265/369348