Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

android espresso login once before running tests

I've been trying to cover my Android app with tests and have started using espresso recently. Pretty impressed with it so far. However most of my app's functionality requires that users are logged in. And since all tests are independent, this requires registering a new user for each test. This works fine however the time required for each test increases considerably because of this.

I am trying to find a way to register a user once in a class (of tests) and then use that same user account to perform all the tests in that class.

One way I have been able to do this is to actually have only one test (@Test) method that runs all the other tests in the order I want. However this is an all or nothing approach, since the gradle cAT task only outputs the results once at the end without providing info about the intermediate tests that may have passed/failed.

I also tried the @BeforeClass approach which however did not work (no gradle output from the class where I had used this even with the debug option and it seemed like it took a long time before it moved on to the next class of tests).

Is there a better approach to register a user once at start of a class and then logout once at the end of testing?

Any help appreciated.

like image 726
source.rar Avatar asked Nov 01 '15 14:11

source.rar


People also ask

How do you assert espresso?

check is a method which accepts an argument of type ViewAssertion and do assertion using passed in ViewAssertion object. matches(withText(“Hello”)) returns a view assertion, which will do the real job of asserting that both actual view (found using withId) and expected view (found using withText) are one and the same.

How do you check espresso visibility?

One simple way to check for a View or its subclass like a Button is to use method getVisibility from View class. I must caution that visibility attribute is not clearly defined in the GUI world. A view may be considered visible but may be overlapped with another view, for one example, making it hidden.


2 Answers

Ideally you would test the login/logout functionality in a set of tests that just test different login/logout scenarios, and let the other tests focus on other use cases. However, since the other scenarios depend on the user being logged in, it sounds like one way to solve this would be to provide a mock version of the app component handling the login. For the other login dependent tests, you would inject this mock at the start and it would return mock user credentials that the rest of the app can work with.

Here's an example where Dagger, Mockito and Espresso is being used to accomplish this: https://engineering.circle.com/instrumentation-testing-with-dagger-mockito-and-espresso-f07b5f62a85b

like image 155
fejd Avatar answered Sep 22 '22 23:09

fejd


I test an app that requires this same scenario. The easiest way I've gotten around this is to split up logging in and out into their own test classes. Then you add all your test classes to a suite, starting and ending with the login and logout suites respectively. Your test suites ends up looking kind of like this.

@RunWith(Suite.class) @Suite.SuiteClasses({         LoginSetup.class,         SmokeTests.class,         LogoutTearDown.class }) 

EDIT: Here is an example of both the LoginSetup and LogoutTearDown tests. This solution really should only be for end-to-end tests and comprise a small portion of your testing efforts. fejd provides a solution for a full testing stack which also needs to be considered.

@LargeTest public class SmokeSetup extends LogInTestFixture {      @Rule     public ActivityTestRule<LoginActivity> mLoginActivity = new ActivityTestRule<>(LoginActivity.class);      @Test     public void testSetup() throws IOException {          onView(withId(R.id.username_field)).perform(replaceText("username"));         onView(withId(R.id.password_field)).perform(replaceText("password"));         onView(withId(R.id.login_button)).perform(click());      }  }  @LargeTest public class LogoutTearDown extends LogInTestFixture {      @Rule     public ActivityTestRule<MainActivity> mMainActivity = new ActivityTestRule<>(MainActivity.class);      @Test     public void testLogout() throws IOException {          onView(withId(R.id.toolbar_menu)).perform(click());         onView(withId(R.id.logout_button)).perform(click());      }  } 
like image 25
James Pullar Avatar answered Sep 19 '22 23:09

James Pullar