I am trying to use mockk anyConstructed but ending with Missing calls inside every { ... } block - kotlin

I am trying to return an object whenever a new object of a class is being created.
I have tried using anyConstructed with a spyk or even mockk object of PredictionCheckFunction
every { anyConstructed<PredictionCheckFunction>() } answers { predictionCheckFunction }
It results in the following error on the above line
io.mockk.MockKException: Missing calls inside every { ... } block.
In Mockito I would do something like this
whenNew(PredictionCheckFunction.class).withNoArguments().thenReturn(predictionCheckFunction);
I want to make sure that every creation of PredictionCheckFunction results in an object of predictionCheckFunction
The example in this Question How to mock a new object using mockk allows me to only run a function on a mock object but not return one already created like above Mockito example thenReturn(predictionCheckFunction); -
Example in referred SO Question -
mockkConstructor(Dog::class)
every { anyConstructed<Dog>().bark() }
Any help on how to do this while creation of a new object, is appreciated.

Related

How to test subscribe call of Observable using Mockk?

I have a function in my ViewModel in which I subscribe to some updates, I want to write a test that will check that after the subscribe is triggered, the specific function is called from the subscribe.
Here is how the function looks:
fun subscribeToTablesUpdates() {
dataManager.getTablesList()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { tablesList ->
updateTablesState(tablesList)
}
}
And this is the test that I wrote:
#Test
fun subscribeToTablesListTest() {
val mockedTablesList = mockk<List<Table>()
every {
viewModel.dataManager.getTablesList()
} returns Observable.just(mockedTablesList)
viewModel.subscribeToTablesUpdates()
verify {
viewModel.updateTablesState(mockedTablesList)
}
}
The issue is that I receive assertion exception without any another info and I don't know how to fix that.
Edit 1: subscribeToTableUpdates() is calling from the init block of ViewModel.
So basically the test itself was done right, but there were linking issue. Since the function of the VM was called from the init block the subscription happened only once, and that created a situation when at the time when I mocked the data service, the observer was already subscribed to the other service. Since the init block is called only once, there is no way to change the implementation of the data service to that observer.
After all this investigation the one thing which I successfully forgot came to my mind again: extract every external dependencies to constructors, so further you could substitute it for the test without any problems like this.

MockK mock method returning Interface Future

Hello I have following problem.
I am trying to mock call of injected executor
to execute given Callable immediately. Later in test arguments of methods called inside Callable are captured and arguments are asserted. Mock example see bellow.
Maven 3, jdk 10-slim, mockk 1.9
//this task should be executed by executor
private val taskCaptor = slot<Callable<Boolean>>()
private val asyncTaskExecutor: LazyTraceThreadPoolTaskExecutor = mockk<LazyTraceThreadPoolTaskExecutor>().apply {
//this was my 1st try, but resutt was java.lang.InstantiationError: java.util.concurrent.Callable
//every { submit(capture(taskCaptor)) } returns CompletableFuture.completedFuture(taskCaptor.captured.call())
//every { submit(any()) } returns CompletableFuture.completedFuture(true)
every { submit(ofType(Callable::class)) } returns FutureTask<Boolean>(Callable { true })
}
later on I have changed Callable interface to implementation, which I have created in tested class and I got another exception.
With same code as above exceptions was
java.lang.InstantiationError: java.util.concurrent.Future
which is return type of submit method.
Is my approach to mocking wrong?
not sure if this is the best way to implemented but for me it worked this way:
private val taskCaptor = slot<Callable<Boolean>>()
private val asyncTaskExecutor: LazyTraceThreadPoolTaskExecutor = mockk<LazyTraceThreadPoolTaskExecutor>().apply {
every { submit(ofType(Callable::class)) } returns mockFuture
every { mockFuture.get() } returns true
}

Kotlin Kovenant returns the same object for all promises

I'm trying to use Kotlin Kovenant because I want a promise-based solution to track my retrofit calls.
What I did first was this:
all (
walkingRoutePromise,
drivingRoutePromise
) success { responses ->
//Do stuff with the list of responses
}
where the promises I pass are those that are resolved at the completion of my retrofit calls. However "responses" is a list of two identical objects. When debugging, I can confirm that two different objects with different values are being passed to the respective resolve methods. However kovenant returns two identical objects (same location in memory)
My next attempt was this:
task {
walkingRoutePromise
} then {
var returnval = it.get()
walkingDTO = returnval.deepCopy()
drivingRoutePromise
} success {
val returnval = it.get()
drivingDTO = returnval.deepCopy()
mapRoutes = MapRoutes(walkingDTO!!, drivingDTO!!)
currentRoute = mapRoutes!!.walking
callback()
}
Where I tried to do the calls one at a time and perform deep copies of the results. This worked for the first response, but then I found that it.get() in the success block - the success block of the second call - is the same unchanged object that I get from it.get() in the "then" block. It seems Kovenant is implemented to use one object for all of its resolutions, but after you resolve once, the single object it uses for the resolutions cannot be changed. What am I supposed to do if I want to access unique values from promise.resolve(object)? Seems like a very broken system.

Authentication test running strange

I've just tried to write a simple test for Auth:
use Mockery as m;
...
public function testHomeWhenUserIsNotAuthenticatedThenRedirectToWelcome() {
$auth = m::mock('Illuminate\Auth\AuthManager');
$auth->shouldReceive('guest')->once()->andReturn(true);
$this->call('GET', '/');
$this->assertRedirectedToRoute('general.welcome');
}
public function testHomeWhenUserIsAuthenticatedThenRedirectToDashboard() {
$auth = m::mock('Illuminate\Auth\AuthManager');
$auth->shouldReceive('guest')->once()->andReturn(false);
$this->call('GET', '/');
$this->assertRedirectedToRoute('dashboard.overview');
}
This is the code:
public function getHome() {
if(Auth::guest()) {
return Redirect::route('general.welcome');
}
return Redirect::route('dashboard.overview');
}
When I run, I've got the following error:
EF.....
Time: 265 ms, Memory: 13.00Mb
There was 1 error:
1) PagesControllerTest::testHomeWhenUserIsNotAuthenticatedThenRedirectToWelcome
Mockery\Exception\InvalidCountException: Method guest() from Mockery_0_Illuminate_Auth_AuthManager should be called
exactly 1 times but called 0 times.
—
There was 1 failure:
1) PagesControllerTest::testHomeWhenUserIsAuthenticatedThenRedirectToDashboard
Failed asserting that two strings are equal.
--- Expected
+++ Actual
## ##
-'http://localhost/dashboard/overview'
+'http://localhost/welcome'
My questions are:
Two similar test cases but why the error output differs? First one the mock Auth::guest() is not called while the second one seems to be called.
On the second test case, why does it fail?
Is there any way to write better tests for my code above? Or even better code to test.
Above test cases, I use Mockery to mock the AuthManager, but if I use the facade Auth::shoudReceive()->once()->andReturn(), then it works eventually. Is there any different between Mockery and Auth::mock facade here?
Thanks.
You're actually mocking a new instance of the Illuminate\Auth\AuthManager and not accessing the Auth facade that is being utilized by your function getHome(). Ergo, your mock instance will never get called. (Standard disclaimer that none of the following code is tested.)
Try this:
public function testHomeWhenUserIsNotAuthenticatedThenRedirectToWelcome() {
Auth::shouldReceive('guest')->once()->andReturn(true);
$this->call('GET', '/');
$this->assertRedirectedToRoute('general.welcome');
}
public function testHomeWhenUserIsAuthenticatedThenRedirectToDashboard() {
Auth::shouldReceive('guest')->once()->andReturn(false);
$this->call('GET', '/');
$this->assertRedirectedToRoute('dashboard.overview');
}
If you check out Illuminate\Support\Facades\Facade, you'll see that it takes care of mocking for you. If you really wanted to do it the way that you were doing it (creating an instance of mock instance of Auth), you'd have to somehow inject it into the code under test. I believe that it could be done with something like this assuming that you extend from the TestCase class provided by laravel:
public function testHomeWhenUserIsNotAuthenticatedThenRedirectToWelcome() {
$this->app['auth'] = $auth = m::mock('Illuminate\Auth\AuthManager');
// above line will swap out the 'auth' facade with your facade.
$auth->shouldReceive('guest')->once()->andReturn(true);
$this->call('GET', '/');
$this->assertRedirectedToRoute('general.welcome');
}

Equivalent of times() in JMockIt?

I dont think minInvocation or maxInvocation is equivalent to times() in Mockito. Is there?
Please see this questions: Major difference between: Mockito and JMockIt
which has not been answered yet by anyone.
Edit
I found the answer myself: Adding it here for others who need this answered:
The solution is to use DynamicPartialMocking and pass the object to the constructor of the Expectations or NonStrictExpectations and not call any function on that object.
Then in the Verifications section, call any function on the object for which you want to measure the number of invocations and set times = the value you want
new NonStrictExpectations(Foo.class, Bar.class, zooObj)
{
{
// don't call zooObj.method1() here
// Otherwise it will get stubbed out
}
};
new Verifications()
{
{
zooObj.method1(); times = N;
}
};
I found the answer myself: Adding it here for others who need this answered:
The solution is to use DynamicPartialMocking and pass the object to the constructor of the Expectations or NonStrictExpectations and not call any function on that object.
Then in the Verifications section, call any function on the object for which you want to measure the number of invocations and set times = the value you want
new NonStrictExpectations(Foo.class, Bar.class, zooObj)
{
{
// don't call zooObj.method1() here
// Otherwise it will get stubbed out
}
};
new Verifications()
{
{
zooObj.method1(); times = N;
}
};