I'm trying to use Mockk to mock a method with context receiver:
class MyClass {
// The method I'm going to mock
context(CallContext)
fun myMethod(a: Int) Int { a }
}
It's hard to get the instance of CallContext in the unit test. So I hope I can write a unit test in this way:
/*
This should work, but I can't get the CallContext instance
with(callContextInstance) {
Every { mockedMyClass.myMethod(1) } returns 2
}
*/
// I hope a unit test can be written like this... But it won't compile now.
with(any<CallContext>) {
Every { mockedMyClass.myMethod(1) } returns 2
}
So what should I do? Thanks in advance.
At the time of writing, MockK does not support context receivers, and it probably won't until context receivers are released - so some time after Kotlin 1.9, so maybe in 2024).
(Context receivers are explicitly described as not ready for production. A stable release won't be available until after the K2 release, and the K2 beta is targeted for Kotlin 1.9, which has a planned release of December 2023.)
That said, if anyone wants to attempt support, then get stuck in! MockK is an community supported open source project that accepts PRs.
Confounding factors
However, there are two hinderances before MockK can fully support context receivers:
Context receivers aren't finished, nor is their current implementation stable. KT-10468. Their implementation could change significantly. Trying to implement support for a moving target is challenging.
IDE support is limited, which makes developing with them difficult (follow KTIJ-20857 for updates)
Workaround
In the meantime, you could adjust your code to allow for manual mocking.
First, adjust MyClass to either be an open class, or introduce a new interface that describes the behaviour you want to mock (code to an interface).
/** Describe the API that [MyClass] will implement */
interface MyClassSpec {
context(CallContext)
fun myMethod(a: Int): Int
}
And then implement the interface
/** Concrete implementation of [MyClassSpec] */
class MyClass: MyClassSpec {
context(CallContext)
override fun myMethod(a: Int): Int = a
}
Now in your test you can create a mock by creating an anonymous object that implements MyClassSpec - and now you have a mock that supports context receivers.
#Test
fun myTest() {
val myClassMock = object : MyClassSpec {
context(CallContext)
override fun myMethod(a: Int): Int = 123
}
}
If I get the idea what exactly do you try to mock, the following works with mockk 1.13.3:
interface CallContext
class MyClass {
context(CallContext)
fun myMethod(a: Int): Int = a
}
class ContextMockTest {
private val myClassMock: MyClass = mockk()
#Test
fun mockContextWorks() {
every {
with(any<CallContext>()) {
myClassMock.myMethod(any())
}
} returns 123
val context = object : CallContext { }
with(context) {
assertEquals(123, myClassMock.myMethod(1))
}
verify {
with(any<CallContext>()) {
myClassMock.myMethod(1)
}
}
}
}
A link to the gist just in case
Related
We are in process of writing Unit test cases using Spock, I am not able to understand the following code snippet in then section varifying the declaration,
then:
1 * service.fraudMigrationOnboardingService.onboard(_) >>
{merchantId -> successCallBack.call(response)}
what is the meaning of the above code.
Because your question is lacking detail, I have to speculate and make an educated guess about your test. :-/
So you have a service with a member or getter fraudMigrationOnboardingService.
fraudMigrationOnboardingService has a method onboard taking a single parameter.
Obviously fraudMigrationOnboardingService is a mock or spy, which is why you can check interactions like 1 * ... on it.
The developer who wrote this test and whom, as it seems, you are too shy to ask about its meaning or who has left your company, wanted something specific to happen when method onboard(_) is called (probably by service) during the test: a call-back method call. Thus she declared the method stub { merchantId -> successCallBack.call(response) } as a replacement for what onboard(_) would normally do in this case. In a spy it would execute the original method, in a mock it would no nothing at all. But obviously that is not the desired behaviour, maybe because the test relies on different behavious later on.
In general, I think a test which is hard to read should be refactored, but anyway, here I am replicating your situation:
package de.scrum_master.stackoverflow
import spock.lang.Specification
class DummyTest extends Specification {
static class Service {
FraudMigrationOnboardingService fraudMigrationOnboardingService
void doSomething(String name) {
println "Doing something"
fraudMigrationOnboardingService.onboard(name)
}
}
static class FraudMigrationOnboardingService {
void onboard(String name) {
println "On-boarding $name"
}
}
static class SuccessCallBack {
void call(int httpResponse) {
println "Callback HTTP response = $httpResponse"
}
}
def "Some service test"() {
given:
def onboardingService = Mock(FraudMigrationOnboardingService)
def service = new Service(fraudMigrationOnboardingService: onboardingService)
def successCallBack = new SuccessCallBack()
def response = 200
when:
service.doSomething("ACME Inc.")
then:
1 * service.fraudMigrationOnboardingService.onboard(_) >>
{ merchantId -> successCallBack.call(response) }
}
}
The console log says:
Doing something
Callback HTTP response = 200
If you would comment out >> { merchantId -> successCallBack.call(response) }, it would only print
Doing something
for a mock and if you also change the Mock(FraudMigrationOnboardingService) into a Spy(FraudMigrationOnboardingService) it would print
Doing something
On-boarding ACME Inc.
Update: Maybe you still don't understand what the closure means, I am not sure. So I will explain it a bit more: As I said, it is just a stub for the onboard(String) method. The method parameter is mapped to merchantId but not used in the stubbed method. Instead the callback is triggered.
I am assigned to add unit test code coverage to a 15 years old legacy project which is not using IoC and 0 unit test. I am not allowed to refactor the code since it works perfect fine on production, management does not want other teams get involved for refactoring such as QA testing, etc.
Service class has a performService method has following code
public void performService(requestMessage, responseMessage) {
UserAccount userAccount = requestMessage.getUserAccount();
GroupAccount groupAccount = requestMessage.getGroupAccount();
Type type = requestMessage.getType();
StaticServiceCall.enroll(userAccount, groupAccount, type);
response.setStatus(Status.SUCCESS);
}
This StaticServiceCall.enroll method is calling remote service. My unit test is
#RunWith(PowerMockRunner.class)
#PrepareForTest(StaticServiceCall.class)
public class EnrollmentServiceTest {
#Test
public void testPerformService() {
mockStatic(StaticServiceCall.class);
doNothing().when(StaticServiceCall.enroll(any(UserAccount.class), any(GroupAccount.class), any(Type.class)));
service.performService(requestMessage, responseMessage);
assertEquals("Enrollment should be success, but not", Status.SUCCESS, response.getStatus);
}
Eclipse complains with The method when(T) in the type Stubber is not applicable for the arguments (void)
Eclipse stops complain if test code change to
mockStatic(StaticServiceCall.class);
doNothing().when(StaticServiceCall.class);
StaticServiceCall.enroll(any(UserAccount.class), any(GroupAccount.class), any(Type.class));
service.performService(requestMessage, responseMessage);
assertEquals("Enrollment should be success, but not", Status.SUCCESS, response.getStatus);
Test case failed with UnfinishedStubbingException. I am using powermock 1.6.6
There is a misconception on your end. You think that you need to say that doNothing() should do nothing.
That is not necessary! As these lines
#PrepareForTest(StaticServiceCall.class) ... and
mockStatic(StaticServiceCall.class);
are sufficient already.
You want to prevent the "real" content of that static method to run when the method is invoked during your test. And that is what mockStatic() is doing.
In other words: as soon as you use mockStatic() the complete implementation of the real class is wiped. You only need to use when/then/doReturn/doThrow in case you want to happen something else than nothing.
Meaning: just remove that whole doNothing() line!
#GhostCat - Thank you for your answer, it solved problem, my misconception is coming from this test case
#Test
public void testEnrollmentServiceSuccess() {
RequestMessage requestMessage = new RequestMessage();
requestMessage.setName("ENROLL");
ResponseMessage responseMessage = new ResponseMessage();
EnrollmentService mockService = mock(EnrollmentService.class);
mockService.performService(any(RequestMessage.class), any(ResponseMessage.class));
mockStatic(ClientManager.class);
when(ClientManager.isAuthenticated()).thenReturn(true);
ServiceImpl service = new ServiceImpl();
service.performService(requestMessage, responseMessage);
verify(mockService).performService(any(RequestMessage.class), any(ResponseMessage.class));
}
Here is the code snippet of ServiceImpl class based name of the request message calling different service class
public void performService(RequestMessage request, ResponseMessage response) {
try {
if (request == null) {
throw new InvalidRequestFormatException("null message");
}
if (!ClientManager.isAuthenticated()) {
throw new ServiceFailureException("not authenticated");
}
// main switch for known services
if ("ENROLL".equals(request.getName())) {
service = new EnrollmentService();
service.performService(request, response);
} else if ("VALIDATE".equals(request.getName())) {
...
Although the test passed,real implementation in EnrollmentService got called and exceptions thrown due to barebone RequestMessage object, then I googled out doNothing, thanks again for your clarification
I am very new to Kotlin.
I have a class that calls a top level function (which makes a http call). I am trying to write unit tests for my class without having it go out to the network.
Is there a way to mock/powermock/intercept the call from my class to the Kotlin top level function?
class MyClass {
fun someMethod() {
// do some stuff
"http://somedomain.com/some-rest/action".httpGet(asList("someKey" to "someValue")).responseString { (request, response, result) ->
// some processing code
}
}
}
It is using the kittinunf/Fuel library for the httpGet call.
It adds a top level function to String that ultimately calls a companion object function in Fuel (Fuel.get()).
The unit test needs to intercept the call to httpGet so that I can return a json string for the test.
I encourage you to encapsulate remote API calls behind an interface that would be injected through constructor to the class using it:
class ResponseDto
interface SomeRest {
fun action(data:Map<String,Any?>): ((ResponseDto)->Unit)->Unit
}
class FuelTests(val someRest: SomeRest) {
fun callHttp(){
someRest.action(mapOf("question" to "answer")).invoke { it:ResponseDto ->
// do something with response
}
}
}
Another way is to to inject a fake Client to be used by Fuel:
FuelManager.instance.client = object: Client {
override fun executeRequest(request: Request): Response {
return Response().apply {
url = request.url
httpStatusCode = 201
}
}
}
Fuel.testMode()
"http://somedomain.com/some-rest/action".httpGet(listOf()).responseString { request, response, result ->
print(response.httpStatusCode) // prints 201
}
It seems that "top level functions" can be seen as static methods in disguise.
And from that point of view, the better answer is: do not use them in such a way. This leads to high, direct coupling; and makes your code harder to test. You definitely want to create some interface Service which all your objects should be using; and then use use dependency injection to equip your client code with some object that implements the Service interface.
By doing so, you also get rid of the requirement to Powermock completely.
im looking for something similar to what i would do with rhino mocks but in groovy.
i sometimes use partial mocks as well.
in ASP -- Rhino mocks
const string criteria = "somecriteriahere";
ISomeRepository mockSomeRepository = MockRepository.GenerateStrictMock<SomeRepository>();
mockSomeRepository.Expect(m => m.GetSomesByNumber(criteria)).Return(new List<Some>() { });
mockSomeRepository.Expect(m => m.GetSomesByName(criteria)).Return(new List<Some>() { });
mockSomeRepository.Expect(m => m.GetSomesByOtherName(criteria)).Return(new List<Some>() { });
mockSomeRepository.SearchForSomes(criteria);
mockSomeRepository.VerifyAllExpectations();
--------note the virtual -------
public class SomeRepository : ISomeRepository {
public virtual IEnumerable<Some> GetSomesByNumber(string num)
{
//some code here
}
public virtual IEnumerable<Some> GetSomesByName(string name)
{
//some code here
}
public virtual IEnumerable<Some> GetSomesByOtherName(string name)
{
//some code here
}
public IEnumerable<Some> SearchForSomes(string criteria) {
this.GetSomesByNumber(criteria); //tested fully seperatly
this.GetSomesByName(criteria); //tested fully seperatly
this.GetSomesByOtherName(criteria); //tested fully seperatly
//other code to be tested
}
}
GetSomesByNumber, GetSomesByName, GetSomesByOtherName would be tested fully seperatly. If i actually provided values and went into those functions, to me, that seems like in integration test where im testing multiple functionalities and not one unit of work.
So, SearchForSomes i would only be testing that method and mocking away all other dependencies.
In Grails
class XService {
def A() {
}
def B() {
def result = this.A()
//do some other magic with result
}
}
I have tried this -- but failed
def XServiceControl = mockFor(XService)
XServiceControl.demand.A(1..1) { -> return "aaa" }
// Initialise the service and test the target method.
//def service = XServiceControl.createMock();
//def service = XServiceControl.proxyInstance()
// Act
//def result = XServiceControl.B(_params);
XServiceControl.use {
new XService().B(_params)
}
Ive got no idea how to do this, does any one know how?
Thanks
If you're using groovy MockFor (e.g. groovy.mock.interceptor.MockFor), then you need to enclode the usage in a .use{} block.
However, it looks like you are calling mockFor from within a grails.test.GrailsUnitTestCase. In that case, there's no need for the .use{} block: the scope of the mock is the whole test.
thanks for your reply ataylor
seem what i was trying to accomplish is something called partial/half mocking. Here are some links.
http://www.gitshah.com/2010/05/how-to-partially-mock-class-and-its.html
http://mbrainspace.blogspot.com/2010/02/partial-half-mocks-why-theyre-good-real.html
https://issues.apache.org/jira/browse/GROOVY-2630
https://issues.apache.org/jira/browse/GROOVY-1823
http://java.dzone.com/articles/new-groovy-171-constructor
I didnt accomplish this, i ended up extracting B() into its own class and injecting a mock of XService into B's class -- Dependency Injection. I was also informed that extracting away dependencies is a better practice for testing. So, i am now very carefull when using this.() :D
Here is my situation:
I want to test on the "HasSomething()" function, which is in the following class:
public class Something
{
private object _thing;
public virtual bool HasSomething()
{
if (HasSomething(_thing))
return true;
return false;
}
public virtual bool HasSomething(object thing)
{
....some algo here to check on the object...
return true;
}
}
So, i write my test to be like this:
public void HasSomethingTest1()
{
MockRepository mocks = new MockRepository();
Something target = mocks.DynamicMock(typeof(Something)) as Something;
Expect.Call(target.HasSomething(new Object())).IgnoreArguments().Return(true);
bool expected = true;
bool actual;
actual = target.HasSomething();
Assert.AreEqual(expected, actual);
}
Is my test written correctly?
Please help me as i can't even get the result as expected. the "HasSomething(object)" just can't be mock in that way. it did not return me 'true' as being set in expectation.
Thanks.
In response to OP's 'answer': Your main problem is that RhinoMocks does not mock members of classes - instead it creates mock classes and we can then set expectations and canned responses for its members (i.e. Properties and Functions). If you attempt to test a member function of a mock/stub class, you run the risk of testing the mocking framework rather than your implementation.
For the particular scenario of the logical path being dependent on the return value of a local (usually private) function, you really need an external dependency (another object) which would affect the return value that you require from that local function. For your code snippet above, I would write the test as follows:
[Test]
public void TestHasSomething()
{
// here I am assuming that _thing is being injected in via the constructor
// you could also do it via a property setter or a function
var sut = new Something(new object());
Assert.IsTrue(sut.HasSomething);
}
i.e. no mocking required.
This is one point of misunderstanding that I often had in the past with regards to mocking; we mock the behaviour of a dependency of the system under test (SUT). Something like: the SUT calls several methods of the dependency and the mocking process provides canned responses (rather than going to the database, etc) to guide the way the logic flows.
A simple example would be as follows (note that I have used RhinoMocks AAA syntax for this test. As an aside, I notice that the syntax that you are using in your code sample is using the Record-Replay paradigm, except that it isn't using Record and Replay! That would probably cause problems as well):
public class SUT
{
Dependency _depend
public SUT (Dependency depend)
{
_depend = depend;
}
...
public int MethodUnderTest()
{
if (_depend.IsReady)
return 1;
else
return -1;
}
}
...
[Test]
public void TestSUT_MethodUnderTest()
{
var dependency = MockRepository.GenerateMock<Dependency>();
dependency.Stub(d => d.IsReady).Return(true);
var sut = new SUT(dependency);
Assert.AreEqual(1, sut.MethodUnderTest());
}
And so the problem that you have is that you are attempting to test the behaviour of a mocked object. Which means that you aren't actually testing your class at all!
In a case like this, your test double should be a derived version of class Something. Then you override the method HasSomething(object) and ensure that HasSomething() calls your one.
If I understand correctly, you are actually interested in testing the method HasDynamicFlow (not depicted in your example above) without concerning yourself with the algorithm for HasSomething.
Preet is right in that you could simply subclass Something and override the behavior of HasSomething to short-circuit the algorithm, but that would require creating some additional test-dummy code which Rhino is efficient at eliminating.
Consider using a Partial Mock Stub instead of a Dynamic Mock. A stub is less strict and is ideal for working with Properties. Methods however require some extra effort.
[Test]
public void CanStubMethod()
{
Foo foo = MockRepository.GenerateStub<Foo>();
foo.Expect(f => f.HasDynamicFlow()).CallOriginalMethod(OriginalCallOptions.NoExpectation);
foo.Expect(f => f.HasSomething()).CallOriginalMethod(OriginalCallOptions.NoExpectation);
foo.Expect(f => f.HasSomething(null)).IgnoreArguments().Return(true);
Assert.IsTrue(foo.HasDynamicFlow());
}
EDIT: added code example and switched Partial Mock to Stub