Proof read robolectric instruction set

This commit is contained in:
Alex Gabor 2022-02-04 15:32:27 +02:00
parent f7f168ad75
commit b6ff7abdd9
2 changed files with 16 additions and 16 deletions

View file

@ -1,7 +1,7 @@
package org.fnives.test.showcase.storage.favourite package org.fnives.test.showcase.storage.favourite
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -21,7 +21,7 @@ class CodeKataFavouriteContentLocalStorageInstrumentedTest {
/** GIVEN just created database WHEN querying THEN empty list is returned */ /** GIVEN just created database WHEN querying THEN empty list is returned */
@Test @Test
fun atTheStartOurDatabaseIsEmpty() = runBlocking { fun atTheStartOurDatabaseIsEmpty() = runTest {
} }
/** GIVEN content_id WHEN added to Favourite THEN it can be read out */ /** GIVEN content_id WHEN added to Favourite THEN it can be read out */

View file

@ -97,16 +97,16 @@ Assert.assertEquals(null, actual)
### 3. Fake ### 3. Fake
So if you are doing these instructions in order, you may remember that in our core integration tests, namely `org.fnives.test.showcase.core.integration.CodeKataAuthIntegrationTest` we actually had Fake implementation of this class. So if you are doing these instructions in order, you may remember that in our core integration tests, namely `org.fnives.test.showcase.core.integration.CodeKataAuthIntegrationTest` we actually had a Fake implementation of this class.
But we never verified that the Fake behaves exactly as will the real thing, so let's do that. But we never verified that the Fake behaves exactly as will the real thing, so let's do that.
Sadly we can't depend on the `org.fnives.test.showcase.core.integration.fake.CodeKataUserDataLocalStorage` since it's in a test module. Sadly we can't depend on the `org.fnives.test.showcase.core.integration.fake.CodeKataUserDataLocalStorage` since it's in a test module.
However with usage of testFixtures we are able to share test classes as we had previously shared an Extension. However with usage of testFixtures we are able to share test classes as we had previously shared an Extension.
Take a look `at code/src/testFixtures/java`, in package `org.fnives.test.showcase.core.integration.fake` We have a `FakeUserDataLocalStorage`. We can use that since it's in the testFixture. Take a look at `core/src/testFixtures/java`, in package `org.fnives.test.showcase.core.integration.fake` We have a `FakeUserDataLocalStorage`. We can use that since it's in the testFixture.
> Reminder: Test fixture plugin creates a new testFixture sourceset where main <- testFixture <- test dependency is created. > Reminder: Test fixture plugin creates a new testFixture sourceset where main <- testFixture <- test dependency is created.
> Also one can depend on another modules testFixtures via testImplementation testFixtures(project('<moduleName>')) > Also one can depend on another module's testFixtures via testImplementation testFixtures(project('<moduleName>'))
So what's better way is there to verify the `Fake` than testing it with the `Real` implementation's test case? So what's a better way to verify the `Fake` than testing it with the `Real` implementation's test case?
To do that we will parametrize our test. Note, it will be different than previous, since it's junit4 and Robolectric. To do that we will parametrize our test. Note, it will be different than previous, since it's junit4 and Robolectric.
@ -152,7 +152,7 @@ Now we validated our fake implementation as well. With this we can be sure our p
## FavouriteContentLocalStorage test ## FavouriteContentLocalStorage test
Our System Under Test will be `org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage` or more precisely it's implementation: `org.fnives.test.showcase.storage.favourite.FavouriteContentLocalStorageImpl` Our System Under Test will be `org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage` or more precisely its implementation: `org.fnives.test.showcase.storage.favourite.FavouriteContentLocalStorageImpl`
What it does is: What it does is:
- it's an abstraction over the Room DAO - it's an abstraction over the Room DAO
@ -171,7 +171,7 @@ Our test class is `org.fnives.test.showcase.storage.favourite.CodeKataFavouriteC
We again need Robolectric to create a Room Database. We again need Robolectric to create a Room Database.
We need to annotate our class with `@RunWith(AndroidJUnit4::class)` We need to annotate our class with `@RunWith(AndroidJUnit4::class)`.
With this Robolectric actually starts our `TestShowcaseApplication` so instead of creating our SUT, we just inject it. However to easily inject with Koin, we extend `KoinTest`: With this Robolectric actually starts our `TestShowcaseApplication` so instead of creating our SUT, we just inject it. However to easily inject with Koin, we extend `KoinTest`:
```kotlin ```kotlin
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@ -206,7 +206,7 @@ fun atTheStartOurDatabaseIsEmpty()= runTest(testDispatcher) {
} }
``` ```
The line `DatabaseInitialization.dispatcher = testDispatcher` may look a bit mysterious, but all we do her is overwrite our original DatabaseInitialization in tests, and use the given Dispatcher as an executor for Room setup. The line `DatabaseInitialization.dispatcher = testDispatcher` may look a bit mysterious, but all we do with it is to overwrite our original DatabaseInitialization in tests, and use the given Dispatcher as an executor for Room setup.
### 1. `atTheStartOurDatabaseIsEmpty` ### 1. `atTheStartOurDatabaseIsEmpty`
@ -350,7 +350,7 @@ We can write UI Tests as well. It is still not as good as Running tests on a Rea
> Note we get to the section where I am the least comfortable with, I don't think I have written enough UI Tests yet, so from now on take evrything with a big grain of salt. Feel free to modify your approach to your need. You may also correct me via issues on GitHub, would be a great pleasure to learn for me. > Note we get to the section where I am the least comfortable with, I don't think I have written enough UI Tests yet, so from now on take evrything with a big grain of salt. Feel free to modify your approach to your need. You may also correct me via issues on GitHub, would be a great pleasure to learn for me.
We can write UI tests that have mocked out UseCases and Business Logic, but I prefer to do a full screen Integration Tests, cause I think my UI changes enough at it is, wouldn't want to maintain one extra testing layer. We can write UI tests that have mocked out UseCases and Business Logic, but I prefer to do a full screen Integration Tests, cause I think my UI changes enough as it is, wouldn't want to maintain one extra testing layer.
So this will be showcased here. But you should be able to write pure UI tests, if you can follow along this section as well if you choose to do so So this will be showcased here. But you should be able to write pure UI tests, if you can follow along this section as well if you choose to do so
### Setup ### Setup
@ -365,7 +365,7 @@ Robot Pattern presented by Jake Wharton here: https://academy.realm.io/posts/kau
There is also a Kotlin specific article [here](https://medium.com/android-bits/espresso-robot-pattern-in-kotlin-fc820ce250f7). There is also a Kotlin specific article [here](https://medium.com/android-bits/espresso-robot-pattern-in-kotlin-fc820ce250f7).
Is the idea to separate the logic of finding your views from the logic of the test. The idea is to separate the logic of finding your views from the logic of the test.
So basically if for example a View Id changes, it doesn't make our behaviour change too, so in this case only our Robot will change, while the Test Class stays the same. So basically if for example a View Id changes, it doesn't make our behaviour change too, so in this case only our Robot will change, while the Test Class stays the same.
For now I will keep the synthetic sugar to the minimum, and just declare my actions and verifications there. Feel free to have as much customization there as you think is necessary to make your tests clearer. For now I will keep the synthetic sugar to the minimum, and just declare my actions and verifications there. Feel free to have as much customization there as you think is necessary to make your tests clearer.
@ -382,7 +382,7 @@ Here is a list of actions we want to do:
- we want to check if we navigated to Main or not - we want to check if we navigated to Main or not
##### So here is the code for our the UI interactions ##### So here is the code for our the UI interactions
.
```kotlin ```kotlin
fun setUsername(username: String) = apply { fun setUsername(username: String) = apply {
onView(withId(R.id.user_edit_text)) onView(withId(R.id.user_edit_text))
@ -424,7 +424,7 @@ Here we took advantage of Espresso. It helps us by being able to perform action
To know what Espresso matchers, assertions are there you just have to use them. It's also easy to extend so if one of your views doesn't have that option, then you can create your own matcher. To know what Espresso matchers, assertions are there you just have to use them. It's also easy to extend so if one of your views doesn't have that option, then you can create your own matcher.
##### Next up, we need to verify if we navigated: ##### Next up, we need to verify if we navigated:
.
```kotlin ```kotlin
fun assertNavigatedToHome() = apply { fun assertNavigatedToHome() = apply {
intended(hasComponent(MainActivity::class.java.canonicalName)) intended(hasComponent(MainActivity::class.java.canonicalName))
@ -438,7 +438,7 @@ fun assertNotNavigatedToHome() = apply {
Here we use Espresso's intents, with this we can verify if an Intent was sent out we can also Intercept it to send a result back. Here we use Espresso's intents, with this we can verify if an Intent was sent out we can also Intercept it to send a result back.
##### Lastly let's verify Errors ##### Lastly let's verify Errors
For Snackbar we still gonna use Espresso, but we have a helper class for that because of we may reuse it in other places. For Snackbar we still gonna use Espresso, but we have a helper class for that because we may reuse it in other places.
So let's add that: So let's add that:
```kotlin ```kotlin
class CodeKataLoginRobot( class CodeKataLoginRobot(
@ -463,7 +463,7 @@ With that our Robot is done, we can almost start Testing. We still need setup in
We open the `org.fnives.test.showcase.ui.codekata.CodeKataAuthActivityInstrumentedTest`. We open the `org.fnives.test.showcase.ui.codekata.CodeKataAuthActivityInstrumentedTest`.
We declare a couple of fields, it will be described later what exacty are those things. We declare a couple of fields, it will be described later what exactly are those things.
```kotlin ```kotlin
private lateinit var activityScenario: ActivityScenario<AuthActivity> private lateinit var activityScenario: ActivityScenario<AuthActivity>
private lateinit var robot: RobolectricLoginRobot private lateinit var robot: RobolectricLoginRobot