How to test Facebook connect with espresso

The Facebook SDK is one of the most used third party SDK on Android and yet it’s quite hard to write UI tests around a simple “Connect with Facebook” button.

Let’s consider this basic flow:

  • Open your login/signup screen
  • Click on “Connect with Facebook” button
  • Go through the Facebook login/signup button with either the native app or a WebView
  • Get redirected to your app with a success/failure/cancel response code that the Facebook SDK handles internally

To approach this problem, we considered 3 solutions.

Solution 1: no mocking

Espresso has support for web views so we could consider leaving the flow as it is and clicking on buttons here and there.

Pros:

  • We’re testing what the user sees, this is an actual end-to-end test so we are closer to the real world.
  • We’re not changing anything in our production code.

Cons:

  • We’re depending on the way the Facebook page is structured. If tomorrow Facebook decides to change their html or if we upgrade the version of the SDK, our tests will break.
  • We’re testing more than our app and a big part of this test might just be obsolete.

Solution 2: mock all the things

With this approach we don’t trust what the Facebook SDK does and we decide to mock every Facebook classes that our app would use. One way of doing this would be to inject a LoginManager, a CallbackManager and a FacebookCallback in our production code and mock them in our test code.

Pros:

  • We don’t depend too much on the Facebook SDK.
  • It’s easy to test different results (success, failure, cancel).
  • We’re focusing on our presentation layer and on the code we wrote.

Cons:

  • Our tests might be unrealistic, we could be testing cases that are not possible in real life.
  • It requires a lot more code than the previous solution. We don’t want to make our tests too complex or we’ll end up requiring tests for our tests.
  • We’re exposing some production code for testing purposes.

Solution 3: mock the intents

Facebook log in works is based on a communication with intents and the good thing is that espresso allows us to mock intents. By taking this approach we could just use the intending/intended trick and we’re good to go.

Pros:

  • We don’t depend too much on the Facebook SDK.
  • It’s easy to test different results (success, failure, cancel).
  • We’re focusing on our presentation layer and on the code we wrote.
  • We’re not changing anything in our production code.

Cons:

  • Our tests might be unrealistic, we could be testing cases that are not possible in real life.
  • We’re relying on an intent based communication. If tomorrow Facebook decides to do something else, we’ll have to rewrite our tests.

Conclusion

We decided to go for solution 3 as it looked like the best compromise for our problem. We want to focus on the code we wrote and more specifically on the presentation layer. We have separate end-to-end tests that make sure that the contract with the Facebook SDK is always valid.

Do you want to see some code? There you go: https://gist.github.com/RomainPiel/e4f64da5b74c23cc27cf

  • Copy AccessTokenCreator into a new package com.facebook in your androidTest source folder.
  • Copy LoginClientCreator into a new package com.facebook.login in your androidTest source folder.
  • Write a test such as that one that launches your activity, clicks on the Facebook button and checks if the FacebookActivity was started.