ursus
05/24/2020, 12:17 PMgildor
05/24/2020, 2:04 PMursus
05/24/2020, 2:05 PMursus
05/24/2020, 2:06 PMDao(Database(Driver))
ursus
05/24/2020, 2:07 PMRepo(Dao(Database(_JdbcDriver_))))
ursus
05/24/2020, 2:08 PMFakeRepo(FakeDao(FakeDatabase(jdbcDriver))
MiSikora
05/24/2020, 2:35 PMursus
05/24/2020, 2:44 PMMiSikora
05/24/2020, 2:48 PMgildor
05/24/2020, 2:48 PMursus
05/24/2020, 2:50 PMursus
05/24/2020, 2:52 PMgildor
05/24/2020, 2:52 PMMiSikora
05/24/2020, 2:52 PMClock
so I can control time, any dependencies that are provided by framework (like location provider) and sometimes web services if I do not care about HTTP layer. I definitely do not fake repositories.gildor
05/24/2020, 2:52 PMursus
05/24/2020, 2:53 PMMiSikora
05/24/2020, 2:53 PMursus
05/24/2020, 2:54 PMursus
05/24/2020, 2:55 PMtesting FooInterfactor which needs FooRepository which needs FooDao which needs FooQueries which need Database which needs JdbcDriver
you are recreating dagger module provider functions, so why not just..use them?gildor
05/24/2020, 2:56 PMursus
05/24/2020, 2:56 PMgildor
05/24/2020, 2:57 PMursus
05/24/2020, 2:57 PMursus
05/24/2020, 2:57 PMgildor
05/24/2020, 2:57 PMMiSikora
05/24/2020, 2:57 PMursus
05/24/2020, 2:58 PMMiSikora
05/24/2020, 2:58 PMMiSikora
05/24/2020, 2:59 PM@Inject constructor()
.ursus
05/24/2020, 2:59 PMursus
05/24/2020, 3:00 PMgildor
05/24/2020, 3:01 PMgildor
05/24/2020, 3:01 PMMiSikora
05/24/2020, 3:02 PMMiSikora
05/24/2020, 3:03 PMursus
05/24/2020, 3:06 PMursus
05/24/2020, 3:06 PMfun createTestFooRepository() {
val moshi = Moshi.Builder()
.add(AppointmentRequestState::class.java, AppointmentRequestStateJsonAdapter())
.add(Uri::class.java, UriJsonAdapter())
.build()
val channelAdapter = Channel.Adapter(
permissionsAdapter = PermissionsColumnAdapter(moshi)
)
val fileStateColumnAdapter = FileStateColumnAdapter()
val stringListColumnAdapter = StringListColumnAdapter(moshi)
val messageAdapter = Message.Adapter(
typeAdapter = MessageTypeColumnAdapter(),
stateAdapter = MessageStateColumnAdapter(),
reactionsAdapter = DbReactionsColumnAdapter(moshi),
f_stateAdapter = fileStateColumnAdapter,
f_uploadSourceInfoAdapter = UploadSourceInfoColumnAdapter(moshi),
a_attendeesAdapter = AttendeesColumnAdapter(moshi),
a_myStatusAdapter = AppointmentRequestStateColumnAdapter(),
e_recipientUsernamesAdapter = stringListColumnAdapter,
e_ccUsernamesAdapter = stringListColumnAdapter
)
val emailAttachmentAdpater = EmailAttachment.Adapter(
fileStateAdapter = fileStateColumnAdapter
)
val accountAdapter = Account.Adapter(
themeAdapter = ThemeColumnAdapter(),
backgroundTypeAdapter = BackgroundTypeColumnAdapter()
)
val driver = JdbcSqliteDriver(<http://JdbcSqliteDriver.IN|JdbcSqliteDriver.IN>_MEMORY)
val database = Database(driver, accountAdapter, channelAdapter, emailAttachmentAdpater, messageAdapter)
return FooRepository(
FooDao(FooQueries(database), BarQueries(database),
)
}
ursus
05/24/2020, 3:06 PMval driver = JdbcSqliteDriver(<http://JdbcSqliteDriver.IN|JdbcSqliteDriver.IN>_MEMORY)
MiSikora
05/24/2020, 3:07 PMursus
05/24/2020, 3:07 PMNetModule.provideMoshi(), DataModule.provideDatabase(moshi, driver)
ursus
05/24/2020, 3:10 PMMiSikora
05/24/2020, 3:12 PMursus
05/24/2020, 3:12 PMMiSikora
05/24/2020, 3:13 PMursus
05/24/2020, 3:13 PMursus
05/24/2020, 3:14 PMursus
05/24/2020, 3:15 PMinit
function to jumpstart the db in a state you want, right? which means you need such method at every level, or in all those functions somehowursus
05/24/2020, 3:15 PM@Test fun testWhatever() {
val repo = createTestFooRepository() { db ->
// init db
}
}
ursus
05/24/2020, 3:15 PMursus
05/24/2020, 3:16 PMursus
05/24/2020, 3:19 PMMiSikora
05/24/2020, 3:19 PMursus
05/24/2020, 3:20 PMMiSikora
05/24/2020, 3:25 PMBurst
or any other parametric test tool). For these reasons I prefer to use real code used in the app and fake the stuff only when I need to control it (like time, or framework elements).MiSikora
05/24/2020, 3:26 PMursus
05/24/2020, 3:28 PMursus
05/24/2020, 3:29 PMursus
05/24/2020, 3:29 PMMiSikora
05/24/2020, 3:29 PMMiSikora
05/24/2020, 3:30 PMursus
05/24/2020, 3:30 PMursus
05/24/2020, 3:30 PMMiSikora
05/24/2020, 3:32 PMursus
05/24/2020, 3:34 PMMiSikora
05/24/2020, 3:36 PMursus
05/24/2020, 3:37 PMursus
05/24/2020, 3:38 PMMiSikora
05/24/2020, 3:38 PMursus
05/24/2020, 3:39 PMMiSikora
05/24/2020, 3:41 PMinsertContact(User(1))
where User(id: Long)
is a factory method with prepopulated data. If behaviours require more semantics they can be hidden behind different test methods.ursus
05/24/2020, 3:42 PMcreateTestFooRepo()
from above? What if you want to tweak the data per test, I'd expect you to expose some lambda with db as param, unless you create some sort of dsl or somethingMiSikora
05/24/2020, 3:47 PMval userStore = factory.userStore
@Test fun foo() {
userStore.insertUser(1)
userStore.insertUser(2)
val presenter = factory.create()
presenter.test {
expectItem() shouldBe intialModelWithBothUsers
sendEvent(RemoveContact(1))
expectItem() shouldBe modelWithoutUser1
}
}
If data preparation gets complex I do write DSLs and so on. The benefit is they can be reused between different modulesursus
05/24/2020, 3:49 PMMiSikora
05/24/2020, 3:53 PMursus
05/24/2020, 3:53 PMMiSikora
05/24/2020, 3:54 PMursus
05/24/2020, 3:55 PMursus
05/24/2020, 3:55 PMMiSikora
05/24/2020, 3:56 PMMiSikora
05/24/2020, 3:56 PMAddContact(1)
ursus
05/24/2020, 3:56 PMMiSikora
05/24/2020, 3:57 PMMiSikora
05/24/2020, 3:57 PMursus
05/24/2020, 3:59 PMMiSikora
05/24/2020, 3:59 PMursus
05/24/2020, 4:00 PMMiSikora
05/24/2020, 4:01 PMursus
05/24/2020, 4:03 PMursus
05/24/2020, 4:25 PM