I can mock a function of a to be tested class in several ways. But how do I mock an object that is created inside of a to be tested method?
I have this to be tested class
#Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7')
import groovyx.net.http.HTTPBuilder
class totest {
def get() {
def http = new HTTPBuilder('http://www.google.com')
def html = http.get( path : '/search', query : [q:'Groovy'] )
return html
}
}
How do I mock http.get so I can test the get function:
class TestTest extends Specification {
def "dummy test"() {
given:
// mock httpbuilder.get to return "hello"
def to_test = new totest()
expect:
to_test.get() == "hello"
}
}
A better approach would be to pass the HTTPBuilder into your constructor and then the test code can pass test mocks instead.
But if you want to mock the class construction going on internal to your code, have a look at mocking constructors and classes using GroovySpy and GroovyMock on here: http://spockframework.org/spock/docs/1.0/interaction_based_testing.html
You would need to do something like the below code:
import spock.lang.Specification
import groovyx.net.http.HTTPBuilder
class totest {
def get() {
def http = new HTTPBuilder('http://www.google.com')
def html = http.get( path : '/search', query : [q:'Groovy'] )
return html
}
}
class TestTest extends Specification{
def "dummy test"() {
given:'A mock for HTTP Builder'
def mockHTTBuilder = Mock(HTTPBuilder)
and:'Spy on the constructor and return the mock object every time'
GroovySpy(HTTPBuilder, global: true)
new HTTPBuilder(_) >> mockHTTBuilder
and:'Create object under test'
def to_test = new totest()
when:'The object is used to get the HTTP result'
def result = to_test.get()
then:'The get method is called once on HTTP Builder'
1 * mockHTTBuilder.get(_) >> { "hello"}
then:'The object under test returns the expected value'
result == 'hello'
}
}
What are you testing here? Do you care how the method gets it's result? Surely you care more that it gets the right result? In that case, the method should be changed so the URL is configurable, then you can stand up a server that returns a known string, and check that string is returned
Related
I'm trying to have some unit tests using groovy.mock.interceptor. I want to assert that a function was indeed called with some specific values as arguments. I can't find how to do that. Any help?
This is what it looks like:
import groovy.mock.interceptor.MockFor
import org.junit.Test
class MyClassTest extends GroovyTestCase {
#Test
void test_correctness_of_passed_arguments() {
def mock = new MockFor(MyClass)
mock.ignore('main')
mock.demand.myFunction{a, b, c -> '0'} // Is this where I should enforce the input params?
mock.use {
def foo = new MyClass()
foo.main() // <--- this is in there that it gets executed
}
mock.expect.verify()
mock.demand.recorded[0] // <--- can I get what has been passed afterwards?
}
}
You can't achieve expected behavior with MockFor class. Ignoring main method has one significant effect - inner method myFunction gets executed, but it happens without a presence of MockInterceptor. You can put a breakpoint in groovy.mock.MockProxyMetaClass class in the beginning of invokeMethod (line 74) and run a debugger to see what happens.
public Object invokeMethod(final Object object, final String methodName, final Object[] arguments) {
if (null == interceptor && !fallingThrough) {
throw new RuntimeException("cannot invoke method '" + methodName + "' without interceptor");
}
Object result = FALL_THROUGH_MARKER;
if (interceptor != null) {
result = interceptor.beforeInvoke(object, methodName, arguments);
}
if (result == FALL_THROUGH_MARKER) {
Interceptor saved = interceptor;
interceptor = null;
boolean savedFallingThrough = fallingThrough;
fallingThrough = true;
result = adaptee.invokeMethod(object, methodName, arguments);
fallingThrough = savedFallingThrough;
interceptor = saved;
}
return result;
}
Invoking foo.main() method in the mock.use {} block invokes this method for non-null interceptor. The result returned by interceptor.beforeInvoke() is equal to FALL_THROUGH_MARKER because main method is marked as ignored. In this case interceptor is set to null temporarily and the method gets invoked in a regular way - it invokes inner myFunction method, but this fact is not recorded due to null interceptor at this point.
Basically, you treat mock object in your test case not as a mock, but rather as a spy object. Groovy standard mocking library does not support spy objects, but you can use e.g. Spock Framework to write tests using spy objects. The test you have shown in the question could look like this using Spock:
import spock.lang.Specification
class ExampleSpec extends Specification {
static class MyClass {
def main() {
return myFunction(0, 0 ,0)
}
def myFunction(def a, def b, def c) {
return '2'
}
}
def "should call myFunction with specific parameters"() {
given:
def foo = Spy(MyClass)
when:
foo.main()
then:
1 * foo.myFunction(0, 0, 0)
and:
0 * foo.myFunction(1,0,0)
}
}
It executes a real foo.main() method, but it mocks foo.myFunction() method and records invocations and tests if the method got invoked with correct parameters - it records that it got invoked once with parameters (0, 0, 0) and that it was not invoked with parameters (1, 0, 0).
IMPORTANT: If you create mock/spy objects from classes and not interfaces, then you need to add cglib-nodep dependency together with Spock.
Okay, this is doable as mock.demand.myFunction takes a normal Closure.
I ended up with something like this:
import groovy.mock.interceptor.MockFor
import org.junit.Test
class MyClassTest extends GroovyTestCase {
#Test
void test_correctness_of_passed_arguments() {
def mock = new MockFor(MyClass)
mock.ignore('main')
def res = []
// the mocked function stores its values in `res` and returns '0'
mock.demand.myFunction(4) {a, b, c ->
res.add([a, b, c])
'0'
}
mock.use {
def foo = new MyClass()
foo.main() // <--- this is in there that it gets executed
}
mock.expect.verify()
res[0] // <--- I can then access the values there
}
}
In the above example, I request myFunction to be called 4 times.
Using Spock framework for java unit testing.
When unit testing a method method1() and method1 is calling a method method2(),In method2() having a code statement as below :
Config config = new Config();
TimeZone tz=TimeZone.getTimeZone(config.getProps().getProperty(Constants.SERVER_TIMEZONE));
The call config.getProps().getProperty(Constants.SERVER_TIMEZONE)
returns America/Cambridge_Bay
In getProps method the property files is fetched from weblogic domain and it will not be available in spcok, its taking path as null.
Please suggest how can this function call be mocked in spock.
We can use meta class injection to mock response method2 in unit testing given block. Here ClassName is the class to which method2 belongs to.
ClassName.metaClass.method2 = { inputParameters ->
return "America/Cambridge_Bay"
}
Also it is advisable to use #ConfineMetaClass([ClassName]) annotation on the unit test to confine the meta class injection changes to your test case.
Lets start with an example which simulates your situation:
class Config {
Properties getProps() {
def props = new Properties()
props.setProperty(Constants.SERVER_TIMEZONE, 'America/Cambridge_Bay')
props
}
}
class Constants {
static String SERVER_TIMEZONE = 'TIMEZONE'
}
Config config = new Config()
def timeZoneID = config.getProps().getProperty(Constants.SERVER_TIMEZONE)
def tz = TimeZone.getTimeZone(timeZoneID)
assert tz.ID == 'America/Cambridge_Bay'
Since method2() doesn't get a Config instance injected into it, mocks are out of the question. So we'll use Groovy's metaClass, at the class level (since instance level is out of the question too, for the same reason). You can override Config.getProps() like this:
Config.metaClass.getProps {
def props = new Properties()
props.setProperty(Constants.SERVER_TIMEZONE, 'Etc/UTC')
props
}
So you can write your Spock test roughly like this:
// import Constants
// import Config class
class FooSpec extends Specification {
#ConfineMetaClassChanges
def "test stuff"() {
when:
Config.metaClass.getProps {
def props = new Properties()
props.setProperty(Constants.SERVER_TIMEZONE, 'America/Cambridge_Bay')
props
}
// Do more stuff
then:
// Check results
}
}
PS
If you can modify method2() to have Config injected, that would be preferable since then you can use Groovy's MockFor.
I have a Groovy/Spock unit test as follows:
public class ThingUnitTest extends Specification {
def "doing a thing delegates to the context"() {
given : def thing = createThing()
when : thing.doThing()
then : 1 * thing.context.doThing()
}
def createThing() {
def thing = new ThingImpl()
thing.context = createThingContext()
return thing
}
def createThingContext() {
def context = Spy(ThingContext)
context.foo = Mock(Foo)
context.bar = Mock(Bar)
return context
}
}
This test will run without problems. However it turns out that I have other tests that need a ThingContext, so I want to move the createThingContext code into a common class:
public class ThingContextFactory extends Specification {
def createThingContext() {
def context = Spy(ThingContext)
context.foo = Mock(Foo)
context.bar = Mock(Bar)
return context
}
}
and then write my unit tests as follows:
public class ThingUnitTest extends Specification {
...
def createThingContext() {
return new ThingContextFactory().createThingContext()
}
}
But now the test fails, with the assertion 1 * thing.context.doThing() failing with zero interactions.
I also tried the following:
public class ThingContextFactory {
def createThingContext() {
def mocking = new MockingApi()
def context = mocking.Spy(ThingContext)
context.foo = mocking.Mock(Foo)
context.bar = mocking.Mock(Bar)
return context
}
But now the tests fail with MockingApi.invalidMockCreation ... InvalidSpec
Note that I do not want to use inheritance here, but move common mocking code into helper classes. But when I do this my spock tests fail.
Is there some proper way to refactor Spock mocking code?
As of Spock 0.7, mock objects can only be created in the test class that uses them, or a superclass thereof. This might change in the next version.
First-timer here, apologies if I've missed anything.
I'm hoping to get around a call to a static method using Spock. Feedback would be great
With groovy mocks, I thought I'd be able to get past the static call but haven't found it.
For background, I'm in the process of retrofitting tests in legacy java. Refactoring is prohibited. I'm using spock-0.7 with groovy-1.8.
The call to the static method is chained with an instance call in this form:
public class ClassUnderTest{
public void methodUnderTest(Parameter param){
//everything else commented out
Thing someThing = ClassWithStatic.staticMethodThatReturnsAnInstance().instanceMethod(param);
}
}
staticMethod returns an instance of ClassWithStatic
instanceMethod returns the Thing needed in the rest of the method
If I directly exercise the global mock, it returns the mocked instance ok:
def exerciseTheStaticMock(){
given:
def globalMock = GroovyMock(ClassWithStatic,global: true)
def instanceMock = Mock(ClassWithStatic)
when:
println(ClassWithStatic.staticMethodThatReturnsAnInstance().instanceMethod(testParam))
then:
interaction{
1 * ClassWithStatic.staticMethodThatReturnsAnInstance() >> instanceMock
1 * instanceMock.instanceMethod(_) >> returnThing
}
}
But if I run the methodUnderTest from the ClassUnderTest:
def failingAttemptToGetPastStatic(){
given:
def globalMock = GroovyMock(ClassWithStatic,global: true)
def instanceMock = Mock(ClassWithStatic)
ClassUnderTest myClassUnderTest = new ClassUnderTest()
when:
myClassUnderTest.methodUnderTest(testParam)
then:
interaction{
1 * ClassWithStatic.staticMethodThatReturnsAnInstance() >> instanceMock
1 * instanceMock.instanceMethod(_) >> returnThing
}
}
It throws down a real instance of ClassWithStatic that goes on to fail in its instanceMethod.
Spock can only mock static methods implemented in Groovy. For mocking static methods implemented in Java, you'll need to use a tool like GroovyMock , PowerMock or JMockit.
PS: Given that these tools pull of some deep tricks in order to achieve their goals, I'd be interested to hear if and how well they work together with tests implemented in Groovy/Spock (rather than Java/JUnit).
Here is how I solved my similar issue (mocking a static method call which is being called from another static class) with Spock (v1.0) and PowerMock (v1.6.4)
import org.junit.Rule
import org.powermock.core.classloader.annotations.PowerMockIgnore
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.rule.PowerMockRule
import spock.lang.Specification
import static org.powermock.api.mockito.PowerMockito.mockStatic
import static org.powermock.api.mockito.PowerMockito.when
#PrepareForTest([YourStaticClass.class])
#PowerMockIgnore(["javax.xml.*", "ch.qos.logback.*", "org.slf4j.*"])
class YourSpockSpec extends Specification {
#Rule
Powermocked powermocked = new Powermocked();
def "something something something something"() {
mockStatic(YourStaticClass.class)
when: 'something something'
def mocked = Mock(YourClass)
mocked.someMethod(_) >> "return me"
when(YourStaticClass.someStaticMethod(xyz)).thenReturn(mocked)
then: 'expect something'
YourStaticClass.someStaticMethod(xyz).someMethod(abc) == "return me"
}
}
The #PowerMockIgnore annotation is optional, only use it if there is some conflicts with existing libraries
A workaround would be to wrap the static method call into an instance method.
class BeingTested {
public void methodA() {
...
// was:
// OtherClass.staticMethod();
// replaced with:
wrapperMethod();
...
}
// add a wrapper method for testing purpose
void wrapperMethod() {
OtherClass.staticMethod();
}
}
Now you can use a Spy to mock out the static method.
class BeingTestedSpec extends Specification {
#Subject BeingTested object = new BeingTested()
def "test static method"() {
given: "a spy into the object"
def spyObject = Spy(object)
when: "methodA is called"
spyObject.methodA()
then: "the static method wrapper is called"
1 * spyObject.wrapperMethod() >> {}
}
}
You can also stub in canned response for the wrapper method if it's supposed to return a value. This solution uses only Spock built-in functions and works with both Java and Groovy classes without any dependencies on PowerMock or GroovyMock.
The way I've gotten around static methods in Groovy/Spock is by creating proxy classes that are substituted out in the actual code. These proxy classes simply return the static method that you need. You would just pass in the proxy classes to the constructor of the class you're testing.
Thus, when you write your tests, you'd reach out to the proxy class (that will then return the static method) and you should be able to test that way.
I have recently found 'spock.mockfree' package, it helps mocking final classes and static classes/methods.
It is quite simple as with this framework, in this case, you would need only to Spy() the class under test and #MockStatic the static method you need.
Example:
We used a static method returnA of StaticMethodClass class
public class StaticMethodClass {
public static String returnA() {
return "A";
}
}
here is the calling code
public class CallStaticMethodClass {
public String useStatic() {
return StaticMethodClass.returnA();
}
}
Now we need to test the useStatic method of CallStaticMethodClass class But spock itself does not support mock static methods, and we support
class CallStaticMethodClassTest extends Specification {
def 'call static method is mocked method'() {
given:
CallStaticMethodClass callStaticMethodClass = Spy()
println("useStatic")
expect:
callStaticMethodClass.useStatic() == 'M'
}
#MockStatic(StaticMethodClass)
public static String returnA() {
return "M";
}
}
We use the #MockStatic annotation to mark which class needs to be mocked
Directly implement the static method that requires mocking under it, the method signature remains the same, but the implementation is different.
Link to the framework:
https://github.com/sayweee/spock-mockfree/blob/498e09dc95f841c4061fa8224fcaccfc53904c67/README.md
I have controller with following code:
def profile = Profile.findByProfileURL(params.profileURL)
and unit test like this:
#TestMixin(GrailsUnitTestMixin)
#TestFor(ProfileController)
#Mock([User])
class ProfileControllerTests {
def void testIndex() {
mockDomain(User, [[firstname: 'Niko',...]])
controller.params.profileURL = 'niko-klansek'
controller.index()
...
}
}
When I run the test I get following exception in the controller referring to :
No signature of method: sportboard.core.profile.Profile.methodMissing() is applicable for argument types: () values: []
So params value profileURL that I have set in the test is not visible from the controller? How can I set params for controller so it is visible?
Exception is cryptic, but it says that your Profile domain class is not mocked. You should add it to #Mock annotation. Also, #TestMixin can be ommited here and you shouldn't use mockDomain directly in test. Just save this user instance. Altogether it should look like this:
#TestFor(ProfileController)
#Mock([User, Profile])
class ProfileControllerTests {
def void testIndex() {
def user = new User(firstName: 'Niko').save()
controller.params.profileURL = 'niko-klansek'
...
}
}