Hello fellow developers,
i have a following problem:
Let's say I have a class called UseCaseX:
class UseCaseX (private val repository: Repository) {
override suspend fun invoke(params: Unit?) = repository.call()
}
Now, this UseCaseX is used in a class ViewModel, like this:
...
val result = async { useCaseX.invoke(null) }
...
Then I use MockK to mock the UseCaseX in a ViewModelTest, like this:
val useCaseX = mockk<UseCaseX>(relaxUnitFun = true)
And I get the following error:
io.mockk.MockKException: no answer found for: UseCaseX(#7).invoke(null, continuation {})
at io.mockk.impl.stub.MockKStub.defaultAnswer(MockKStub.kt:90)
at io.mockk.impl.stub.MockKStub.answer(MockKStub.kt:42)
So obviously the UseCaseX.invoke(params) function gets extended during async{} with an additional parameter and there is no answer for it so far.
Question: how can I provide the answer for the mock in that case?
use withContext(Dispatchers.Default) instead of async. Should work!
Related
I have a problem with MockK.
I have a class:
#Service
class ItemServiceImpl(private val varPuObjectMapper: VarPuObjectMapper) : OutboundAdvicesService {
override suspend fun getItemsForWarehouse(warehouseId: String): ItemsDTO {
// do stuff
}
override suspend fun getPickingListsForWarehouse(warehouseId: String): PickingListsDTO {
val groupedOutboundAdvices = getItemsForWarehouse(warehouseId)
// do other stuff
}
}
and a test for this class:
class ItemServiceGroupingTest : FunSpec({
val warehouseId = "1"
val myObjectMapper = MyObjectMapper()
val itemService = mockk<ItemServiceImpl>()
beforeTest {
val items1 = myObjectMapper
.getObjectMapper()
.readValue(Mockups.ITEMS_1, ItemsDTO::class.java)
coEvery {
itemService.getItemsForWarehouse(warehouseId)
} returns items1
}
test("should get items for warehouse with ID 1") {
val itemsDTO = itemService.getItemsForWarehouse(warehouseId)
// assertions here
}
test("should get picking lists for warehouse with ID 1") {
val pickingLists = itemService.getPickingListsForWarehouse(warehouseId)
// assertions here
}
})
Now the first test passes successfully, but the second one fails:
no answer found for: ItemServiceImpl(#1).getPickingListsForWarehouse(1, continuation {})
io.mockk.MockKException: no answer found for: ItemServiceImpl(#1).getPickingListsForWarehouse(1, continuation {})
at app//io.mockk.impl.stub.MockKStub.defaultAnswer(MockKStub.kt:93)
From what I understand, this fails cause the getPickingListsForWarehouse method is not mocked. Is it possible to call a real method using MockK? I tried to use spyk instead of mockk, and I tried mockk with relaxed = true, but it got me nowhere...
The problem with the second test is that you are trying to call a method from a mock without specified behavior. The first test passes because you already set the value which should be returned for the method call itemService.getItemsForWarehouse(warehouseId) in this statement in beforeTest:
coEvery {
itemService.getItemsForWarehouse(warehouseId)
} returns items1
You have to do the same for getPickingListsForWarehouse or call a real method like:
every { itemService.getPickingListsForWarehouse(warehouseId) } answers { callOriginal() }
But then you have to use spyk instead of mock.
However, if you are asserting the object which you provided within the mock, you are not testing the real implementation of the method under test. You are just testing the mock, so if you change the implementation of your method this test still will be passing. beacuse it doesn't call your real object.
I have an interface that communicates with my presenter who checks whether the fields of a form are valid.
My interface is:
interface MainView {
fun showMessage(data: LoginEntity)
fun showEmailError()
fun showPasswordError()
}
My method in the presenter is like that:
fun sendForm(loginData: LoginDataPresentation, view: MainView) {
if (isValid()) {
view.showMessage(mapData(loginData))
} else if (isValidPassword()) {
view.showPasswordError()
} else {
view.showEmailError()
}
}
My test class with KotlinTest:
class LoginPresentationKtTest : StringSpec() {
init {
"given a bunch of Login Data should be matched successfully" {
forAll(EmailGenerator(), PasswordGenerator(), { email: String, password: String ->
val loginData: LoginDataPresentation(email, password)
val mockMainView = mockMainView()
sendForm(loginData, mockMainView())
})
}
}
private fun mockMainView(): MainView {
//How to mock?????
}
}
Using the KotlinTest library, is there any way to verify that the call to the showMessage method of the MainView class is done provided that the email and password generated is always correct? Is it possible to use a mock library like mockito?
With the response of the user #mkobit, the following modification can be made using Mockito-Kotlin, with which the test would be as follows:
class LoginPresentationKtTest : StringSpec() {
init {
"given a bunch of Login Data should be matched successfully" {
forAll(EmailGenerator(), PasswordGenerator(), { email: String, password: String ->
val loginData = LoginDataPresentation(email, password)
val mockMainView = Mockito.mock(MainView::class.java)
sendForm(loginData, mockMainView)
verify(mockMainView).showMessage()
true
})
}
}
}
At each execution of the loop, it will be checked if the verify () function has been called. If the execution flow is the expected one, it will proceed to the next execution of the loop. If the verify () function fails, an error will occur in the console indicating that the test has failed.
Is there any better solution?
You mentioned Mockito, so I'll show you can example. I'm going to also use the nhaarman/mockito-kotlin library that makes it more expressive and easier to use in Kotlin.
import com.nhaarman.mockito_kotlin.mock
val mockMainView: MainView = mock()
This is basically equivalent to val mockMainView = Mockito.mock(MainView::class.java) from Mockito.
In Kotlin, we can get a more concise and compact code due to some of its features.
If you want to do some stubbing (like return values, exceptions, etc.) you could use the whenever (Mockito.when(T methodCall)) API.
See the documentation for details.
I'm going to skip that for now.
So, now you would call for method:
sendForm(loginData, mockMainView)
Then, you can perform verification.
Using mockito-kotlin method verify (Mockito.verify(T mock)) the behavior.
import com.nhaarman.mockito_kotlin.verify
verify(mockMainView).showPasswordError()
verify(mockMainView).showEmailError()
Using any() (Mockito.any(Class<T> type)) to not just verify method is called with any value.
import com.nhaarman.mockito_kotlin.any
verify(mockMainView).showMessage(any())
There is support for other argument matchers if you want to be more explicit with what is being passed in.
Note that Mockito also supports opt-in mocking of final classes/methods.
The example for Gradle would be something like adding a file to src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker with the contents of mock-maker-inline.
References:
Mockito Javadoc
mockito-kotlin Wiki documentation
How to mock Kotlin extension function using Mockito or PowerMock in tests? Since they are resolved statically should they be tested as static method calls or as non static?
I think MockK can help you.
It supports mocking extension functions too.
You can use it to mock object-wide extensions:
data class Obj(val value: Int)
class Ext {
fun Obj.extensionFunc() = value + 5
}
with(mockk<Ext>()) {
every {
Obj(5).extensionFunc()
} returns 11
assertEquals(11, Obj(5).extensionFunc())
verify {
Obj(5).extensionFunc()
}
}
If you extension is a module-wide, meaning that it is declared in a file (not inside class), you should mock it in this way:
data class Obj(val value: Int)
// declared in File.kt ("pkg" package)
fun Obj.extensionFunc() = value + 5
mockkStatic("pkg.FileKt")
every {
Obj(5).extensionFunc()
} returns 11
assertEquals(11, Obj(5).extensionFunc())
verify {
Obj(5).extensionFunc()
}
By adding mockkStatic("pkg.FileKt") line with the name of a package and file where extension is declared (pkg.File.kt in the example).
More info can be found here: web site and github
First of all, Mockito knows nothing Kotlin specific language constructs. In the end, Mockito will have a look into the byte code. Mockito is only able to understand what it finds there and what looks like a Java language construct.
Meaning: to be really sure, you might want to use javap to deassemble the compiled classfiles to identify the exact names/signatures of the methods you want to mock.
And obviously: when that method is static, you have to user PowerMock, or JMockit; if not, you should prefer to with Mockito.
From a java point of view, you simply avoid mocking static stuff; but of course, things get really interesting, now that different languages with different ideas/concepts come together.
Instance extension functions can be stubbed and verified like this with the help of mockito-kotlin:
data class Bar(thing: Int)
class Foo {
fun Bar.bla(anotherThing: Int): Int { ... }
}
val bar = Bar(thing = 1)
val foo = mock<Foo>()
with(foo) {
whenever(any<Bar>().bla(any()).doReturn(3)
}
verify(foo).apply {
bar.bla(anotherThing = 2)
}
I use mockk library.
For extension file write java name, like this:
#file:JvmName(name = "ExtensionUtils")
package myproject.extension
...
And for fast codding I created file with different extension mocks:
object FastMock {
fun extension() = mockkStatic("myproject.extension.ExtensionUtils")
fun listExtension() = mockkStatic("myproject.extension.ListExtensionUtils")
}
In test call this:
FastMock.listExtension()
every { itemList.move(from, to) } returns Unit
I have problem unit testing method inside closure called by call_user_func() example :
public function trans($lang, $callback)
{
$this->sitepress->switch_lang($lang);
call_user_func($callback);
}
on controller :
public function sendMail()
{
$foo = $baz = 'something';
$mail = $this->mailer;
$this->helper->trans_c('en', function() use($foo, $baz, $mail) {
$mail->send('Subject', $foo, $baz);
});
}
test case :
public function testSomething()
{
$helperMock = Mockery::mock('Acme\Helper');
$helperMock->shouldReceive('trans_c')->once(); // passed
$mailMock = Mockery::mock('Acme\Mail');
$mailMock->shouldReceive('send')->once(); // got should be called 1 times instead 0
$act = new SendMailController($helperMock, $mailMock);
$act->sendMail();
}
how can I ensure that ->send() method is called inside closure trans_c()
I tried with
$helperMock->shouldReceive('trans_c')->with('en', function() use($mailMock) {
$mailMock->shouldReceive('send');
});
no luck. :(
well it works fine with passing Mockery::type('Closure') in the second param of trans_c, but I really need to ensure that method send from mailer class is called.
A mocked class does not execute the real code by default. If you mock the helper it will check that the calls are being made but won't execute the anonymous function.
With mockery, you can configure the expectation so that the real method will be executed: passthru();
Try this:
$helperMock = Mockery::mock('Acme\Helper');
$helperMock
->shouldReceive('trans_c')
->once()
->passthru()
;
This is explained in the docs.
EDIT
Maybe you don't really need to mock the helper. If you mock the Mail class and expect the send method to be called once, just let the real helper do it.
I'm following the accepted answer in this question but I'm getting a NullReferenceException.
What I need is having a partial mock stub a property (both getter and setter) to behave like a stub (as a simple automatic property). Currently I am able to stub the getter but not the setter.
Is this possible?
EDIT: this is a simple example, I hope it helps explaining my problem.
public class SomeClass
{
public virtual string SomeProperty
{
get{ return SomeMethodDependingOnDBOrAspSession(); }
set{ SomeMethodDependingOnDBOrAspSession(value); } // I want to avoid calling this setter implementation
}
}
var partialMock = MockRepository.GeneratePartialMock<SomeClass>();
partialMock.Stub(p => p.SomeProperty); // I want SomeProperty to behave as an automatic property
When using a PartialMock you can get auto-implemented property like behavior by using PropertyBehavior feature of Rhino Mocks. Given the class in your question, the following nunit test passes for me.
[Test]
public void TestPartialMock()
{
var someClass = MockRepository.GeneratePartialMock<SomeClass>();
someClass.Stub(x => x.SomeProperty).PropertyBehavior();
string val = "yo!";
Assert.DoesNotThrow(() => someClass.SomeProperty = val);
Assert.AreEqual(val, someClass.SomeProperty);
}
If you don't need a PartialMock you could use a Stub which has property behavior by default. You'd simply replace the first two lines of the test with:
var someClass = MockRepository.GenerateStub<SomeClass>();