mockk, get error when using mockkstatic for stub static function - android-unit-testing

using io.mockk 1.11.0
having some class with #JvmStatic function
class LogUtil {
#JvmStatic
fun logData(jsonStr: String) {
val jsonObj = getDataJson(jsonStr)
if (jsonObj == null) {
Log.e("+++", "+++ wrong json")
}
// ......
}
}
data util
class DataUtil {
#JvmStatic
fun getDataJson(json: String): JSONObject? {
return try {
JSONObject(json)
} catch (e: Exception) {
null
}
}
}
The test is to verify the Log.e(...) is called when a null is returned from getDataJson().
#Test
fun test_() {
io.mockk.mockkStatic(android.utils.Log::class)
io.mockk.mockkStatic(DataUtil::class)
every { DataUtil.getDataJson(any()) } returns null //<== error points to this line
LogUtil.logData("{key: value}")
verify(exactly = 1) { android.utils.Log.e("+++", any()) }
}
got error
io.mockk.MockKException: Failed matching mocking signature for
left matchers: [any()]
if change to every { DataUtil.getDataJson("test string") } returns null, it will get error
MockKException: Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock
How to use mockkStatic for a #JvmStatic unction?

The use of mockkStatic is correct, but DataUtil is not static.
If your code is kotlin, must use object instead class:
object DataUtil { .. }
object LogUtil { .. }
PD: Use unmockkStatic in #After method for avoid side effects that may affect other test.

Related

How to get the string I put into a Error instance?

Basicly I got this,
// MyPackage.swift
enum Error: LocalizedError {
case general(String)
}
func foobar() throws {
throw Error.general("haha")
}
do {
try foobar()
} catch Error.general(let message) {
// will print "haha"
print(message)
}
And then in the unit test, I need to check if I got the exact same error,
import Quick
import Nimble
import MyPackage
class MySpec: QuickSpec {
override func spec() {
describe("") {
let input = "haha"
let count = 2
let expectation = Error.general("非纯数字字符串无法使用本方法")
context("输入_" + input) {
it("预期_" + expectation.localizedDescription) {
// got the error
// but expectation.localizedDescription was not what I looking for
expect(try numberStringByAddingZerosInto(input, tillReach: count))
.to(throwError(expectation))
}
}
}
}
}
It worked, but expectation.localizedDescription was not "haha", which made the name of the test case useless.
I also tried expectation.errorDescription with no luck.
Where could I get it?
And why is it like this?
override errorDescription var
enum Error: LocalizedError {
case general(String)
var errorDescription: String? {
switch self {
case .general(let errorMessage):
return errorMessage
}
}
}
Now, you can also write do-catch block by this
do {
try foobar()
} catch let error {
print(error.localizedDescription)
}

Kotlin equivalent of Swift Expectations/Promises

I am trying to write some UnitTests for my native mobile applications, but have ran into a roadblock in my Android Tests. Specifically, I am struggling to find an example of Kotlin's version of Swift's Expectations/Promises..
I've found examples of Kotlin Promises, but they seem to be way more complicated than needed...
For example, here is a test for the login API function in my iOS project:
func testLogin() {
/// Prepare for login
if CURRENT_USER != nil {
logout()
}
/// Login
let promise = expectation(description: "User is logged in.")
// 1. Given
var isSuccess: Bool = false
// 2. When
User.login(username: maleUsername, password: malePassword, success: {
isSuccess = true
promise.fulfill()
}) { (_, agreeToTerms) in
XCTFail()
}
wait(for: [promise], timeout: maxTimeOut)
// 3. Then
XCTAssertNotNil(CURRENT_USER)
XCTAssertTrue(isSuccess)
/// Logout
logout()
}
This is pretty simple to me. I have an asynchronous method login that has two possible completion blocks: success and failure; and I need to wait for one of them to complete before evaluating. To do this, I create a promise before the call, then I fulfill the promise in the two completion blocks, and I wait for the promise to fulfill before running my assertions.
Now in Kotlin, I have a similar test:
private val loginFragment = LoginFragment()
#Test
fun loginTest() {
val username = ""
val password = ""
// TODO: Create Promise
loginFragment.loginViewModel
.login(username, password)
.observe(loginFragment, Observer {
loginFragment.activity?.onResult(it?.result,
onSuccess = {
// TODO: Fill Promise
},
onValidationError = {
// TODO: Fail Test
})
})
// TODO: Assertions
}
But I can't find an equivalent of swift's promises..
Does one exist in Kotlin? If not, how would I implement a version of my Swift's testLogin method in Kotlin?
You can use Kotlin coroutines, for example:
#Test
fun loginTest() {
val result = runBlocking {
val loginResult = login()
loginResult
}
if (result == "Success") {
// do your work when Success
} else {
// do your work when Error
}
}
suspend fun login(): String = suspendCoroutine { continuation ->
val username = ""
val password = ""
loginFragment.loginViewModel
.login(username, password)
.observe(loginFragment, Observer {
loginFragment.activity?.onResult(it?.result,
onSuccess = {
continuation.resume("Success")
},
onValidationError = {
continuation.resume("Error") // take a look for other methods, e.g. resumeWithException(exception)
})
})
}
To use coroutines you need to add next lines to app's build.gradle file dependencies:
final KOTLIN_COROUTINES_VERSION = '1.0.1'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$KOTLIN_COROUTINES_VERSION"
Hope it will help.
I found this Kotlin Promise lib closer to Swift Promises.
Using this library your test would like.
#Test
fun loginTest() {
val username = ""
val password = ""
Promise<Boolean, Exception> { promise ->
loginFragment.loginViewModel
.login(username, password)
.observe(loginFragment, Observer {
loginFragment.activity?.onResult(it?.result,
onSuccess = {
promise.resolve(true)
},
onValidationError = {
promise.reject(Exception("Login error"))
})
})
}.whenComplete {
when (it) {
is Promise.Result.Success -> {
assert(it.value)
}
}
}
}
I wrote in 20 minutes an implementation that looks like swift's expectation, but he is not sophisticated, use only for simple cases it does the work well.
typealias XCTestExceptionHandler = (KTTestException?) -> Unit
fun TestCase.expectation(description: String): KTTestExpectation {
return KTTestExpectation(description)
}
fun TestCase.waitFor(expectation: KTTestExpectation, timeout: Long, handler: XCTestExceptionHandler) {
expectation.handler = handler
Thread.sleep(timeout)
expectation.timedOut()
}
class KTTestExpectation(private val description: String) {
private var isFulfilled = false
var handler: XCTestExceptionHandler? = null
fun fulfill() {
Handler(Looper.getMainLooper()).postDelayed({
invokeHandlerWith(null)
}, 2)
}
fun timedOut() {
invokeHandlerWith(KTTestException("Timed out: $description"))
}
private fun invokeHandlerWith(error: KTTestException?) {
if (isFulfilled) return
isFulfilled = true
handler?.invoke(error)
error?.let { Assert.fail("Timed out: $description") }
}
}
class KTTestException(message:String): Exception(message)
Using:
fun testExpectation() {
var nb = 0
val expectation = expectation("Test")
MyAsyncFunc {
nb = 5
expectation.fulfill()
}
waitFor(expectation, 1000) { error ->
assertEquals(5, nb)
}
}
If anyone has the courage to convert the original code to Kotlin Here are the links:
https://github.com/apple/swift-corelibs-xctest/blob/main/Sources/XCTest/Public/Asynchronous/XCTWaiter.swift
https://github.com/apple/swift-corelibs-xctest/blob/main/Sources/XCTest/Public/Asynchronous/XCTestExpectation.swift

Throw an exception from a singleton initializer

I have a singleton that manages a set of data. If for some reason that data is unavailable I'd like the creation of the singleton to fail by throwing an exception. The compiler isn't a fan of marking the getter with throws NOTE: I realize I could handle this other ways but now I'm curious if it's even possible.
class Foo {
class var `default`: Foo {
let instance = Foo()
return instance
}
private init() throws {
// Throw if unable to load required data...
}
}
You can do it like this(code from my playground), downside every call of your singleton will have to be done with try.
enum FooError : Error {
case RuntimeError(String)
}
class Foo {
static func defaultFoo() throws -> Foo {
if let instance = Foo("Success") {
return instance
} else {
throw FooError.RuntimeError("Singleton is not created")
}
}
private init?(_ parameter: String?) {
if let _ = parameter {
print("Init Succeded")
} else {
print("Init failed")
return nil;
}
}
}
try Foo.defaultFoo()

TypeScript: How to get a subclass's method to return parent this

I am trying to figure out how to get this to work correctly:
class A {
john(): B {
return this; // <-- ERROR HERE
}
}
class B extends A {
joe(): B {
return this;
}
}
So I can do method chaining:
let instance = new B();
instance.john().joe();
Of course, TypeScript complains that this doesn't match B's type.
Simply use the this keyword as the return type of methods that return this:
class A {
john(): this {
return this;
}
}
class B extends A {
joe(): this {
return this;
}
}
let instance = new B();
instance.john().joe();
You can also omit the return types. TypeScript will infer the return types as this because the methods return this:
class A {
john() {
return this;
}
}
class B extends A {
joe() {
return this;
}
}
This feature is called Polymorphic this types and was introduced in TypeScript 1.7. See the GitHub PR for details.

How to add operator extension as a part of context of the specific class without subclassing?

I'm trying to utilize operators for Wicket, which is painfully verbose.
My most wanted feature is to use an unary "+" to add() a component.
But it will be needed to work inside context of every MarkupContainer descendants.
Use should be like this:
class SomePage() : WebPage() {
init {
// SomePage{} context
+Label("someLabel","Some label")
// instead of this.add(Label("someLabel","Some label"))
+object : StatelessForm<Unit>("someForm") {
init {
// StatelessForm{} context
+Label("fieldLabel","Field label")
+RequiredTextField("someField")
}
}
}
}
Is it possible to implement this now without subclassing everything? Some imaginary syntax of what i want:
extend org.apache.wicket.MarkupContainer {
operator fun<T: Component> T.unaryPlus():T {
// add() is called as a method of a MarkupContainer instance
add(this) // this#MarkupContainer.add(this#unaryPlus)
return this
}
}
https://kotlinlang.org/docs/reference/extensions.html
https://kotlinlang.org/docs/reference/operator-overloading.html
Using the unaryPlus operator (+Component) is harder in this context since, as the unary implies, it's a single operand operator (single input). There's a sort of hacky solution though:
class ExtOf<out T : MarkupContainer>(val self: T) {
companion object {
private val lastConfiguredContainer = ThreadLocal<ExtOf<MarkupContainer>?>()
fun <T : MarkupContainer> configure(container: T, configurer: ExtOf<T>.() -> Any?): T {
val currentLast = lastConfiguredContainer.get()
try {
val newCurrent = ExtOf(container)
lastConfiguredContainer.set(newCurrent)
newCurrent.configurer()
} finally {
lastConfiguredContainer.set(currentLast)
}
return container
}
}
operator fun <T2 : Component> T2.unaryPlus(): T2 {
val container = lastConfiguredContainer.get()
container!!.self.add(this) //TODO throw a nice exception explaining how ot use the `configure`
return this
}
}
fun <T : MarkupContainer> T.configure(configurer: ExtOf<T>.() -> Any?) = ExtOf.configure(this, configurer)
The above maintains information about last configured MarkupContainer in a ThreadLocal private variable that is used to supply the receiver of add method.
You can then write:
class SomePage() : WebPage() {
init {
configure {
+Label("someLabel", "Some label")
+StatelessForm<Unit>("someForm").configure {
// StatelessForm{} context
+Label("fieldLabel", "Field label")
+RequiredTextField<Long>("someField")
}
}
}
}
As I mentioned above the solution while works is far from being pretty. It can be confusing (as often overloaded operators are) so I'd advice using the regular add like so:
class SomePage() : WebPage() {
init {
add(
Label("someLabel", "Some label"),
StatelessForm<Unit>("someForm").apply {
// StatelessForm{} context
add(
Label("fieldLabel", "Field label"),
RequiredTextField<Long>("someField")
)
}
}
}
}
I guess ideally there would be a library similar to anko but for wicket.
I believe it's not possible
The problem is that unaryPlus operator fun cannot have any params. You want to use unaryPlus inside MarkupContainer class, but you also want to add component (other class, other reference with technicly could be a param)
The only way I see it could work would be with subclassing (Component subclass MarkupContainer) and unaryPlus perator extension to MarkupContainer
class Label(name: String, b: String) : Component() {}
open class MarkupContainer() {
fun add(component: Component) {
println("added" + this)
}
}
open class Component() : MarkupContainer() {}
open class StatelessForm<T>(name: String) : Component()
operator fun Component.unaryPlus() {
add(this)
}
class SomePage() : Component() {
init {
add(Label("someLabel", "Some label"))
+Label("someLabel", "Some label")
+object : StatelessForm<Unit>("someForm") {
init {
// StatelessForm{} context
+Label("fieldLabel", "Field label")
}
}
}
}