nirazo
02/26/2021, 3:35 AMexecute
method from APP to get value.
The return values from UseCases are defined as Results, and puts it in Output of UseCase, and returns it to my APP.
Define of Results:
sealed class Results<out T, out S> {
class Success<out T>(val data: T) : Results<T, Nothing>()
class Failure<out S>(val cause: S) : Results<Nothing, S>()
}
Sample useCase and it’s IO:
interface SampleUseCaseInterface {
suspend fun execute(): sampleUseCaseIO.Output
}
class sampleUseCase() : SampleUseCaseInterface {
override suspend fun execute(): sampleUseCaseIO.Output =
sampleUseCaseIO.Output(Results.Success("success!"))
}
class sampleUseCaseIO {
data class Output(val results: Results<String, Error>)
}
Now, I want to mock the execute method of UseCase and return an arbitrary Output in order to write a Unit Test in an iOS app.
However, now the following error is displayed and it is not possible to create an arbitrary output.
Both data and error are required to be included in Results, and the required Output cannot be created.
Is there any way to avoid this?
Also, is it possible to realize a mechanism like Either on the iOS side with Kotlin/Native?Yev Kanivets
02/26/2021, 5:57 AMResult
seems to use inline
classes, which aren’t well supported by testing/mocking libraries and objc-c interop when used with KMP. So we deprecated use of Result
in KMP code, and introduced own own substitute in our team.Cicero
02/26/2021, 7:20 AMnirazo
02/26/2021, 10:47 AMYev Kanivets
02/26/2021, 10:48 AMOutcome
for example.Result
, which you need.Anders
03/03/2021, 8:59 PMResults
is perhaps that Swift does not support covariance and contravariance at all, despite them being present in Objective-C.Results<Nothing, MyFailure>
and Results<MyData, Nothing>
to be subtypes of Results<MyData, MyFailure>
, despite it working in Kotlin and Objective-C since they both support covariance.
For your Results
type to work in Swift, you will likely need to change the T
and S
type parameters to be invariant instead of covariant. You can also try to do a as!
force cast, assuming the Swift compiler won't stop you with its naunces around ObjC lightweight generics.nirazo
03/22/2021, 11:52 AMsealed class Results<out T, out S> {
class Success<out T, out S>(val data: T) : Results<T, S>()
class Failure<out T, out S>(val cause: S) : Results<T, S>()
}
In my unit test code on iOS, I can make stub for object for success result as below.
let success = ResultsSuccess<ObjectForSuccess, ObjectForError>(data: someData)
Cicero
03/22/2021, 2:36 PMsealed class Either<out L, out R> {
data class Left<out L>(val value: L) : Either<L, Nothing>()
data class Right<out R>(val value: R) : Either<Nothing, R>()
val isRight get() = this is Right<R>
val isLeft get() = this is Left<L>
fun <L> left(a: L) = Left(a)
fun <R> right(b: R) = Right(b)
}
fun <L, R, T> Either<L, R>.fold(left: (L) -> T, right: (R) -> T): T =
when (this) {
is Either.Left -> left(value)
is Either.Right -> right(value)
}
fun <L, R, T> Either<L, R>.flatMap(f: (R) -> Either<L, T>): Either<L, T> =
fold({ this as Either.Left }, f)
fun <L, R, T> Either<L, R>.map(f: (R) -> T): Either<L, T> =
flatMap { Either.Right(f(it)) }
Doesn’t translate well to Objective-C, maybe I’m going to look at your approach 🙂