I have a simple class like
class SomeClass {
def foo() {
def bar= bar()
switch( bar ) {
return something based on format
}
}
def bar() {
return someValue
}
}
I've already written complete unit tests for the bar(). Now I need to write unit tests for foo() which is heavily dependant on the use of bar() method. I don't want to duplicate the setup phase as done for bar(), so I'd like to mock it by simply returning values I want.
I'm aware that Groovy supports this sort of "mocking" easily by simply defining it like SomeClass.property = "Hello World". Also, this can be done with collaborators as SomeClass.service = myMockedService. But I've not found a way to accomplish this with methods inside the unit under tests. Is there?
I tried with MockFor as in
def uut = new MockFor( SomeClass )
uut.demand.bar{ /* some values */ }
uut.use {
assert uut.foo() == expected
}
but it gives me
groovy.lang.MissingMethodException: No signature of method: groovy.mock.interceptor.MockFor.foo() is applicable for argument types: () values: []
UPDATE
In fact, I came up with a simple solution of using sub-classing. In the test method I create a subclass of SomeClass where I override the method I wish to mock/stub. After this, using an instance of the subclass gives me what I need.
This seems a bit rough, though. Any other suggestions on this?
If you want to mock the value returned by bar() for a single instance of SomeClass you can use metaprogramming. Try the following in the Groovy console:
class SomeClass {
def foo() {
}
def bar() {
return 'real value'
}
}
def uut = new SomeClass()
uut.metaClass.bar = {
return 'mock value'
}
assert 'mock value' == uut.bar()
If you want to mock bar() for all instances of SomeClass, replace this:
uut.metaClass.bar = {
return 'mock value'
}
with:
SomeClass.metaClass.bar = {
return 'mock value'
}
Related
Suppose I have a class like this:
class MyClass {
method data-is-valid {
return self!get-data ~~ m{^From};
}
method !get-data {
return 'From Internet';
}
}
where !get-data method gets some data from Internet.
Is it possible to mock that method so that it returns my own hardcoded data so I can test the module without connecting to the Internet?
Ideally, the solution should not modify the definition of the class in any way.
NOTE: A similar question exists regarding unittesting subroutines of modules.
I would first refactor to pull the fetching logic out to a different object, and make MyClass depend on it:
class Downloader {
method get-data {
return 'From Internet';
}
}
class MyClass {
has Downloader $.downloader .= new;
method data-is-valid {
return $!downloader.get-data ~~ m{^From};
}
}
This is an example of dependency inversion, which is a helpful technique for making code testable (and tends to make it easier to evolve in other ways too).
With this change, it is now possible to use the Test::Mock module to mock Downloader:
use Test;
use Test::Mock;
subtest 'Is valid when contains From' => {
my $downloader = mocked Downloader, returning => {
get-data => 'From: blah'
};
my $test = MyClass.new(:$downloader);
ok $test.data-is-valid;
check-mock $downloader,
*.called('get-data', :1times);
}
subtest 'Is not valid when response does not contain From' => {
my $downloader = mocked Downloader, returning => {
get-data => 'To: blah'
};
my $test = MyClass.new(:$downloader);
nok $test.data-is-valid;
check-mock $downloader,
*.called('get-data', :1times);
}
You probably want to take a look at Test::Mock. From its SYNOPSIS:
use Test;
use Test::Mock;
plan 2;
class Foo {
method lol() { 'rofl' }
method wtf() { 'oh ffs' }
}
my $x = mocked(Foo);
$x.lol();
$x.lol();
check-mock($x,
*.called('lol', times => 2),
*.never-called('wtf'),
);
Hi #julio i suggest you take a look at the wrap function for routines, this should do what you need... https://docs.raku.org/language/functions#Routines ... this includes use soft; pragma to prevent inlining
Probably the best idea would be to refactor the code (see Jonathan's answer)
However, If you cannot for some reason, there are still alternatives:
If the method is public you can simply create a subclass and override the method.
For example:
use Test;
class MyClass {
method data-is-valid {
return self.get-data ~~ m{^From};
}
method get-data {
return 'From Internet';
}
}
class MyClassTester is MyClass {
method get-data {
return 'Foobar';
}
}
my MyClassTester $class = MyClassTester.new;
nok $class.data-is-valid, 'Mocked class has invalid data';
done-testing;
If the method is private, you can use wrap as stated on p6steve's answer. However you need introspection in order to modify the private method.
It can be done like this:
use Test;
class MyClass {
method data-is-valid {
return self!get-data ~~ m{^From};
}
method !get-data {
return 'From Internet';
}
}
my $class = MyClass.new;
my Method:D $get-data = $class.^find_private_method: 'get-data';
$get-data.wrap: { 'Foobar' };
nok $class.data-is-valid, 'Mocked class has invalid data';
done-testing;
So I have a method that looks something like this:
public Foo method() {
...
return service.get();
}
service is an external dependency of the class.
My test code:
Foo mockServiceResponse = Mockito.mock(Foo.class);
when(service.get()).thenReturn(mockServiceResponse);
In my unit test I inject a mock created with Mockito and set a when for service.get() so my question is, how do I test the return value of method?
If I just check if mockServiceResponse is equal to method() the test doesnt check much since if someone changes method to:
public Foo method() {
...
Foo f = service.get();
f.setId(null);
return f;
}
My test will still pass, which is obviously wrong, so how should I test this?
CLARIFICATION: What I want to test is that method doesnt change the object returned from service.get() (meaning, I want the second stub to fail my test), problem is mock objects just ignore methods called on them (like setId()) without failing the test.
You'll do something like:
Service service = mock(Service.class);
Foo aResponse = new Foo(1);
when(service.get()).thenReturn(aResponse);
MyClass subject = new MyClass(service);
Foo result = subject.method();
assertNull(result.getId());
You can use Mockito's verifyNoMoreInteractions or verifyZeroInteractions to assert that no calls were made to the service response object.
#Test
public void should_not_mutate_response() {
// given
Service mockService = Mockito.mock(Service.class);
Foo mockServiceResponse = Mockito.mock(Foo.class);
when(mockService.get()).thenReturn(mockServiceResponse);
SubjectUnderTest subjectUnderTest = new SubjectUnderTest(mockService);
// when
Foo result = subjectUnderTest.method();
//then
Mockito.verifyZeroInteractions(mockServiceResponse);
}
Or if you expect some particular interactions with the response object after all:
#Test
public void should_set_id_on_response() {
// given
...
// when
...
// then
Mockito.verify(mockServiceResponse).setId(ArgumentMatchers.anyInt());
Mockito.verifyNoMoreInteractions(mockServiceResponse);
}
I'm struggling to understand something about Spock interactions in a Groovy unit test.
I have the following types:
public interface Bar {
public String getMessage();
}
public class Foo {
private Bar bar;
public void setBar(Bar bar) {
this.bar = bar;
}
public String getMessage() {
return bar.getMessage();
}
}
and I then wrote the following Groovy/Spock test:
class FooSpec extends Specification {
private Bar bar;
private Foo foo;
def setup() {
bar = Mock(Bar) { getMessage() >> "hello" }
foo = new Foo()
foo.bar = bar
}
def "say hello"() {
expect:
foo.message.equals("hello")
}
def "say goodbye"() {
setup:
bar.getMessage() >> "goodbye"
expect:
foo.message.equals("goodbye")
}
}
The code creates a mock Bar instance in the setup, initializes Bar.getMessage() to return hello, and assigns this to a new Foo instance.
The first test verifies that foo.getMessage() is equal to hello.
The second test tries to modify the bar mock so that it's getMessage method returns goodbye. We then expect that foo.getMessage() (which delegates to bar.getMessage()) would then return goodbye. However the test fails as follows:
FooSpec:say goodbye:26 Condition not satisfied
because foo.message is still equal to hello.
I also tried the following:
def "say goodbye"() {
when:
bar.getMessage() >> "goodbye"
then:
foo.message.equals("goodbye")
}
and:
def "say goodbye"() {
when:
no_op()
then:
bar.getMessage() >> "goodbye"
foo.message.equals("goodbye")
}
But both failed with the same hello does not equal goodbye message.
I'm probably still thinking in Mockito mode, and assume that an interaction is the equivalent of a when(...).thenReturn(...) expression, and that later interactions would override earlier interactions.
Is there a simple way using Spock to declare an interaction in a setup method, then override that interaction in a test case? Or do I need to remove the setup() method and basically add a setup: block to each test case?
That's a tricky one. As stated in the docs, interactions declared in a then-block have precedence over interactions declared earlier. However, interactions declared in a then-block are scoped to the previous when-block. (This allows to have multiple when-then pairs.) Hence your last try doesn't work, but the following will:
def setup() {
bar.message >> "hello"
}
def "say goodbye"() {
when:
def msg = foo.message
then:
bar.message >> "goodbye"
msg == "goodbye"
}
I agree that it would be good for interactions declared in test methods to always override interactions declared in setup methods. Anyway, a good alternative to overriding interactions is for each test method to call a helper method that sets up the expected interactions for that test method.
I'm struggling to understand something about Spock interactions in a Groovy unit test.
I have the following types:
public interface Bar {
public String getMessage();
}
public class Foo {
private Bar bar;
public void setBar(Bar bar) {
this.bar = bar;
}
public String getMessage() {
return bar.getMessage();
}
}
and I then wrote the following Groovy/Spock test:
class FooSpec extends Specification {
private Bar bar;
private Foo foo;
def setup() {
bar = Mock(Bar) { getMessage() >> "hello" }
foo = new Foo()
foo.bar = bar
}
def "say hello"() {
expect:
foo.message.equals("hello")
}
def "say goodbye"() {
setup:
bar.getMessage() >> "goodbye"
expect:
foo.message.equals("goodbye")
}
}
The code creates a mock Bar instance in the setup, initializes Bar.getMessage() to return hello, and assigns this to a new Foo instance.
The first test verifies that foo.getMessage() is equal to hello.
The second test tries to modify the bar mock so that it's getMessage method returns goodbye. We then expect that foo.getMessage() (which delegates to bar.getMessage()) would then return goodbye. However the test fails as follows:
FooSpec:say goodbye:26 Condition not satisfied
because foo.message is still equal to hello.
I also tried the following:
def "say goodbye"() {
when:
bar.getMessage() >> "goodbye"
then:
foo.message.equals("goodbye")
}
and:
def "say goodbye"() {
when:
no_op()
then:
bar.getMessage() >> "goodbye"
foo.message.equals("goodbye")
}
But both failed with the same hello does not equal goodbye message.
I'm probably still thinking in Mockito mode, and assume that an interaction is the equivalent of a when(...).thenReturn(...) expression, and that later interactions would override earlier interactions.
Is there a simple way using Spock to declare an interaction in a setup method, then override that interaction in a test case? Or do I need to remove the setup() method and basically add a setup: block to each test case?
That's a tricky one. As stated in the docs, interactions declared in a then-block have precedence over interactions declared earlier. However, interactions declared in a then-block are scoped to the previous when-block. (This allows to have multiple when-then pairs.) Hence your last try doesn't work, but the following will:
def setup() {
bar.message >> "hello"
}
def "say goodbye"() {
when:
def msg = foo.message
then:
bar.message >> "goodbye"
msg == "goodbye"
}
I agree that it would be good for interactions declared in test methods to always override interactions declared in setup methods. Anyway, a good alternative to overriding interactions is for each test method to call a helper method that sets up the expected interactions for that test method.
I want to test that the controller calls the service method with the correct arguments. What is the best way to do that?
My current plan is to use mockFor and then through the closure check the value passed in. Is there a better way to do the test through mockFor or the mocked object similar to what I can do with mockito to perform this same method call argument value test?
class HappyControllerTests extends ControllerUnitTestCase {
:
void testSomeValue() {
def mockControl = mockFor(HappyService)
def givenSomeItem = null
mockControl.demand.serviceMethod(1..99) { String someItem -> givenSomeItem = someItem; }
controller.happyService = mockControl.createMock()
controller.someAction()
mockControl.verify()
assertEquals("specific value", givenSomeItem)
}
}
Thanks!
I rarely use mockFor as I find groovy's built in metaClass stuff and as ClassName to be easier to work with and more powerful, I'd do this:
void testSomeValue() {
def givenSomeItem = null
controller.happyService = [
serviceMethod: { String someItem -> givenSomeItem = someItem }
] as HappyService
controller.someAction()
assertEquals "specific value", givenSomeItem
}