title: Testing Android Room with LiveData, Coroutines and Transactions
body: <p>I want to test my database layer and I have caught myself in a catch-22 type of a situation.</p>
  
  <p><strong>The test case consists of two things:</strong></p>
  
  <ul>
  <li>Save some entities</li>
  <li>Load the entities and assert the database mapping works as expected</li>
  </ul>
  
  <p><strong>The problem, in short, is that:</strong></p>
  
  <ul>
  <li><code>Insert</code> is a <code>suspend</code> method, which means it needs to be run in <code>runBlocking{}</code></li>
  <li><code>Query</code> returns a <code>LiveData</code> of the result, which is also asynchronous. Therefore it needs to be observed. There's <a href="https://stackoverflow.com/questions/44270688/unit-testing-room-and-livedata">this</a> SO question that explains how to do that.</li>
  <li>In order to observe the LiveData according to the above link, however, I must use the <code>InstantTaskExecutorRule</code>. (Otherwise I get <code>java.lang.IllegalStateException: Cannot invoke observeForever on a background thread.</code>)</li>
  <li><strong>This works for most of the cases, but it does not work with <code>@Transaction</code>-annotated DAO methods. The test never finishes.</strong> I think it's deadlocked on waiting for some transaction thread.</li>
  <li>Removing the <code>InstantTaskExecutorRule</code> lets the Transaction-Insert method finish, but then I am not able to assert its results, because I need the rule to be able to observe the data.</li>
  </ul>
  
  <h3>Detailed description</h3>
  
  <p>My <code>Dao</code> class looks like this:</p>
  
  <pre><code>@Dao
  interface GameDao {
      @Query("SELECT * FROM game")
      fun getAll(): LiveData&lt;List&lt;Game&gt;&gt;
  
      @Insert
      suspend fun insert(game: Game): Long
  
      @Insert
      suspend fun insertRound(round: RoundRoom)
  
      @Transaction
      suspend fun insertGameAndRounds(game: Game, rounds: List&lt;RoundRoom&gt;) {
          val gameId = insert(game)
          rounds.onEach {
              it.gameId = gameId
          }
  
          rounds.forEach {
              insertRound(it)
          }
      }
  </code></pre>
  
  <p>The test case is:</p>
  
  <pre><code>@RunWith(AndroidJUnit4::class)
  class RoomTest {
      private lateinit var gameDao: GameDao
      private lateinit var db: AppDatabase
  
      @get:Rule
      val instantTaskExecutorRule = InstantTaskExecutorRule()
  
      @Before
      fun createDb() {
          val context = ApplicationProvider.getApplicationContext&lt;Context&gt;()
          db = Room.inMemoryDatabaseBuilder(
              context, AppDatabase::class.java
          ).build()
          gameDao = db.gameDao()
      }
  
      @Test
      @Throws(Exception::class)
      fun storeAndReadGame() {
          val game = Game(...)
  
          runBlocking {
              gameDao.insert(game)
          }
  
          val allGames = gameDao.getAll()
  
          // the .getValueBlocking cannot be run on the background thread - needs the InstantTaskExecutorRule
          val result = allGames.getValueBlocking() ?: throw InvalidObjectException("null returned as games")
  
          // some assertions about the result here
      }
  
      @Test
      fun storeAndReadGameLinkedWithRound() {
          val game = Game(...)
  
          val rounds = listOf(
              Round(...),
              Round(...),
              Round(...)
          )
  
          runBlocking {
              // This is where the execution freezes when InstantTaskExecutorRule is used
              gameDao.insertGameAndRounds(game, rounds)
          }
  
          // retrieve the data, assert on it, etc
      }
  }
  
  </code></pre>
  
  <p>The <code>getValueBlocking</code> is an extension function for <code>LiveData</code>, pretty much copypasted from the link above</p>
  
  <pre><code>fun &lt;T&gt; LiveData&lt;T&gt;.getValueBlocking(): T? {
      var value: T? = null
      val latch = CountDownLatch(1)
  
      val observer = Observer&lt;T&gt; { t -&gt;
          value = t
          latch.countDown()
      }
  
      observeForever(observer)
  
      latch.await(2, TimeUnit.SECONDS)
      return value
  }
  </code></pre>
  
  <p>What's the proper way to test this scenario? I need these types of tests while developing the database mapping layer to make sure everything works as I expect. </p>