TLDR : Here is a minimally reproduceable example. You do not need a Supabase account / database to get the error.
I have some code like this, which performs some simple transformation of data before saving it in Supabase
suspend fun saveClones(owner: String, repository: String, clones: GitHubClones): List<ResultClone> {
val zeClones = clones.clones.map {
Clone(
owner = owner,
repository = repository,
count = it.count,
uniques = it.uniques,
timestamp = it.timestamp
)
}
return client.postgrest["clone"].insert(zeClones, upsert = true, onConflict = "owner, repository, timestamp").decodeList<ResultClone>()
}
I'd like to check that the data going in the insert call is what I expect it to be. I've tried to mock the client using mockk as such
val supabaseClient = mockk<SupabaseClient>()
val postgrest = mockk<Postgrest>()
val postgrestBuilder = mockk<PostgrestBuilder>()
val postgrestResult = PostgrestResult(body = null, headers = Headers.Empty)
every { supabaseClient.postgrest } returns postgrest
every { postgrest["path"] } returns postgrestBuilder
coEvery { postgrestBuilder.insert(values = any<List<Path>>()) } returns postgrestResult
but when running my test, I am facing the following error :
java.lang.IllegalStateException: Plugin rest not installed or not of type Postgrest. Consider installing Postgrest within your supabase client builder
at io.github.jan.supabase.postgrest.PostgrestKt.getPostgrest(Postgrest.kt:172)
at nl.lengrand.GitHubTrafficStoreTest$setUp$1.invoke(GitHubTrafficStoreTest.kt:53)
at nl.lengrand.GitHubTrafficStoreTest$setUp$1.invoke(GitHubTrafficStoreTest.kt:53)
What would be the correct way to unit test that function? It looks like I also cannot really use test containers with Supabase, making integration tests equally as difficult.
I think, that extension properties can't be mocked like that.
My interpretation of extension property is, that it is in byte code present as static getter (basically same principe how extension functions are implemented), which 1st arugment is instance of "extended" type. And in Kotlin is such getter visible as property. That is why mockStatic
should do the job.
When I modify code
@BeforeTest
fun setUp() {
mockkStatic(SupabaseClient::postgrest)
every { supabaseClient.postgrest } returns postgrest
}
@AfterTest
fun tearDown() {
unmockkStatic(SupabaseClient::postgrest)
}
I got new error
kotlinx.serialization.SerializationException: Serializer for class 'Person' is not found.
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
at kotlinx.serialization.internal.Platform_commonKt.serializerNotRegistered(Platform.common.kt:92)
so I would say, that this approach would work.