question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Unit testing Firestore with Robolectric

See original GitHub issue

What feature would you like to see?

Demo: https://gitlab.com/drizzd/firebaserobodemo

I would like to test my app, including the Firestore code paths, with Robolectric. Unfortunately, Firestore and Robolectric depend on different versions of protobuf. I don’t suppose it makes sense to just exclude one of the two?

debugUnitTestCompileClasspath - Compile classpath for compilation 'debugUnitTest' (target  (androidJvm)).                                                                                          
+--- com.google.firebase:firebase-firestore:21.4.1                                                                                                                                                 
    +--- io.grpc:grpc-protobuf-lite:1.21.0                                                                                                                                                        
    |    +--- io.grpc:grpc-api:1.21.0 (*)                                                                                                                                                         
    |    \--- com.google.protobuf:protobuf-lite:3.0.1                                                                                                                                             
[...]                                                                                                                                                                                              
+--- org.robolectric:robolectric:4.3.1                                                                                                                                                             
|    +--- org.robolectric:shadows-framework:4.3.1                                                                                                                                                  
|    |    +--- com.google.android.apps.common.testing.accessibility.framework:accessibility-test-framework:2.1                                                                                     
|    |    |    \--- com.google.protobuf:protobuf-java:2.6.1                                                                                                                                        
|    |    \--- com.android.support:support-annotations:28.0.0      

There is also another issue with the SharedPreferences filename on Windows, for which I have submitted to Robolectric: https://github.com/robolectric/robolectric/issues/5529.

How would you use it?

I would like to use AndroidX Test unit tests which are based on Robolectric in order to efficiently test Android apps which use Firestore. Combined with the Firebase emulator suite it would make a very powerful testing environment.

Dependency Error

For reference, this is the runtime error:

java.lang.NoSuchMethodError: com.google.firestore.v1.MapValue.makeImmutable()V

	at com.google.firestore.v1.MapValue.<clinit>(com.google.firebase:firebase-firestore@@21.4.1:490)
	at com.google.firebase.firestore.UserDataReader.parseMap(com.google.firebase:firebase-firestore@@21.4.1:290)
	at com.google.firebase.firestore.UserDataReader.parseData(com.google.firebase:firebase-firestore@@21.4.1:251)
	at com.google.firebase.firestore.UserDataReader.convertAndParseDocumentData(com.google.firebase:firebase-firestore@@21.4.1:232)
	at com.google.firebase.firestore.UserDataReader.parseSetData(com.google.firebase:firebase-firestore@@21.4.1:75)
	at com.google.firebase.firestore.DocumentReference.set(com.google.firebase:firebase-firestore@@21.4.1:166)
	at com.google.firebase.firestore.DocumentReference.set(com.google.firebase:firebase-firestore@@21.4.1:146)

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
var-constcommented, Mar 25, 2020

I believe the issue is that future.get blocks the same thread that the callback is going to be invoked on; therefore, the callback never gets a chance to be invoked. Trying out your repro app (thanks for preparing it!) with logging enabled (FirebaseFirestore.setLoggingEnabled(true)), I see that Firestore receives the response from the server, but the callback is never invoked. I’m not very familiar with how waiting for asynchronous events works in Robolectric, sorry; I don’t think this is something specific to Firestore. It would appear that you would need to call either flushForegroundThreadScheduler or flushBackgroundThreadScheduler before you can poll the future.

1reaction
drizzdcommented, Mar 21, 2020

That fixes the version conflict. However, the callbacks are not invoked in the following test. It passes after the 10 second sleep:

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class FirebaseTest {
    private val context = ApplicationProvider.getApplicationContext<Context>()

    @Test
    fun write() {
        val settings = FirebaseFirestoreSettings.Builder()
            .setHost("127.0.0.1:8080")
            .setSslEnabled(false)
            .setPersistenceEnabled(false)
            .build()

        FirebaseApp.initializeApp(context)
        val firestore = FirebaseFirestore.getInstance()
        firestore.firestoreSettings = settings
        firestore.collection("ponys").document("foo").set(mapOf("key" to "bar"))
            .addOnSuccessListener {
                throw Exception("success")
            }
            .addOnFailureListener {
                throw Exception("failure")
            }
            .addOnCanceledListener {
                throw Exception("canceled")
            }
        Thread.sleep(10000)
    }

Looking at the network traffic, it seems that no GRPC/Protobuf traffic happens:

image

As opposed to the Node.js version which works as expected:

const firebase = require('firebase/app');
require('firebase/firestore');

let firebaseApp;

async function main() {
  firebaseInit();

  try {
    await run();
  } finally {
    firebaseDelete();
  }
}

function firebaseInit() {
  firebaseApp = firebase.initializeApp({
    apiKey: "<...>",
    authDomain: "<...>.firebaseapp.com",
    databaseURL: "https://<...>.firebaseio.com",
    projectId: "<...>",
    storageBucket: "<...>.appspot.com",
    messagingSenderId: "<...>",
    appId: "<...>"
  });
  firebaseApp.firestore().settings({
    host: 'localhost:8080',
    ssl: false
  });
}

function firebaseDelete() {
  firebaseApp.delete();
}

async function run() {
  let firestore = firebaseApp.firestore();
  await firestore.collection('ponys').doc('foo').set({key: 'bar'});
}
main();

image

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to Unit Test Firestore (In Roboelectric) : r/Firebase - Reddit
I the calls made using instance never return. But the same initialization works when the app is ran on device(Emulator), and yes it...
Read more >
Build unit tests | Firebase Security Rules - Google
This method clears all data associated with a particular project in the locally running Firestore instance. Use this method to clean-up after tests....
Read more >
Testing Jetpack Security with Robolectric | by Matthew Dolan
Writing a unit test. We can start to write a simple test to ensure reading and writing to this SharedPreferences works as expected...
Read more >
Unit Testing with Mockito & Firebase - Stack Overflow
One of the tests involves an interactor file I wrote ( DatabaseInteractor.java ) that connects to Google Firestore. The default constructor sets ...
Read more >
Android BDD with Robolectric and Espresso — how to refactor ...
Once we have our DSL functions placed in the sharedTest directory, we can easily use them to write our unit and instrumentation tests....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found