Can't able to create mock in inheritance relationship with spock - spock

I am new to spock.I have created mock object in normal class its works fine. But when we have inheritance like structure as below then I can't able to mock the things properly its gives error (null pointer). Any one have idea how we can do it in spock.
Class Parent{
Third getThird(){
return third;
}
}
Class Child extend Parent{
Object method1(){
String msg=getThird().someMethod(); // need to mock this line
return object;
}
}
given:
Third third=Mock()
Child child=new Child()
child.getThird(false) >> third
third.someMethod() >> "xyz"
when :
Object object=child.method1()
then:
//comparing the things

Can you try this?:
given:
def third = Mock(Third)
Child.metaClass.getThird = {
third
}
when :
Object object=child.method1()
then:
1 * thirdMocked.someMethod() >> "xyz"
and:
//comparing the things
cleanup:
Child.metaClass = null

you can mock classes in Spock like any interfaces :
given:
def thirdMock = Mock(Third) {
someMethod() >> "xyz"
}
def child = Mock(Child) {
third >> thirdMock
}
when :
def object = child.method1()
then:
//comparing the things
however, it's usualy a symptom of a code not really testable. in your case, you should probably make 'third' injectable, and then inject a mock.

Related

Mocking methods in grails integration test carries over to other tests

I have an integration test where I sometimes want to mock the return of a service method. However, I have seen that once I mock that method, the subsequent tests that call it will also use the mocked function.
Is this normal? If so, how can I have test which sometimes use mocked functions and sometimes use the real implementation?
Here is my code:
MyController {
def someService
def save(){
...
def val = someService.methodToMock()//sometimes want to mock other times, not
...
}
}
MyTest {
def "test 1"(){
...
//I want to mock here
myController.someService.metaClass.methodToMock = { [] }
...
myController.save()
}
def "test 2"(){
...
//I don't want to mock here, however
// it is returning the mocked results
myController.save()
}
}
In general you don't want to change anything to do with metaclasses in integration or functional tests, only in unit tests. It's expected that you'll be doing this in unit tests and there's automatic support for restoring the original metaclass after each test or after each test class runs depending on the version of Grails and how things are configured. But this isn't the case in integration tests.
There are several different approaches you can use. If you use untyped dependency injection, e.g. def someService, then you can overwrite the real service instance with anything you want, and as long as it has the method(s) that you'll be invoking during the test method the controller won't know or care that it's not the real service.
I like to use a map of closures in this case, since Groovy will invoke a closure as if it were a method. So for 'test 1' you could do this:
def "test 1"() {
...
def mockedService = [methodToMock: { args -> return ... }]
myController.someService = mockedService
...
myController.save()
}
This works because you get a new instance of the controller for each test, and you change the service just for that instance, but the real service isn't affected at all.
Your controller invokes someService.methodToMock(), which is actually someService.get('methodToMock').call(), but the map access and closure invocation syntax can take advantage of Groovy's syntactic sugar to look like a regular method call.
Another option is to subclass the service and override the method(s) that you want, and replace the injected instance with that. This or something like it would be necessary if you type the dependency injection (e.g. SomeService someService). Either create a named subclass (class TestSomeService extends SomeService { ... }) or create an anonymous inner class:
def "test 1"() {
...
def mockedService = new SomeService() {
def methodToMock(args) {
return ...
}
}
myController.someService = mockedService
...
myController.save()
}
Altering the metaClass in one test will absolutely affect other tests. You're altering the groovy system, and need to perform some special cleanup if you're metaClassing. At the end my methods where I metaClass, I call a function to revoke the metaClass changes, passing in the name of the class that was metaClassed, and the instance metaClassed if there was one.
def "some authenticated method test"() {
given:
def user = new UserDomain(blah blah blah)
controller.metaClass.getAuthenticatedUser = { return user }
when:
controller.authenticatedMethod() // which references the authenticated user
then:
// validate the results
cleanup:
revokeMetaClassChanges(theControllerClass, controller)
}
private def revokeMetaClassChanges(def type, def instance = null) {
GroovySystem.metaClassRegistry.removeMetaClass(type)
if (instance != null) {
instance.metaClass = null
}
}
Alternatively, you can just mock the service in the test. A method similar to that mentioned by Burt could be:
def "some test"() {
given:
def mockSomeService = mockFor(SomeService)
mockSomeService.demand.methodToMock(1) { def args ->
return []
}
controller.someService = mockSomeService.createMock()
when:
controller.save()
then:
// implement your validations/assertions
}

Grails: How to mock properties for domain object with non-domain abstract base class

I have a grails 2.2.4 app with a domain class Monster:
class Monster {
int aggression
}
I can mock and test it like so:
import spock.lang.*
class MonsterSpec extends Specification {
def "property mocks work"() {
given:
def m = Mock(Monster)
m.aggression >> 5
expect:
m.aggression == 10
}
}
Recently I decided to give it an abstract base class (not a domain object itself) so that I could share method implementations among my many Monster-like classes:
abstract class Entity {} // Not under /domain
class RefactoredMonster extends Entity {
int aggression
}
But then a thousand simple tests all broke, like so:
import spock.lang.*
class MonsterSpec extends Specification {
def "property mocks work"() {
given:
def m = Mock(RefactoredMonster)
m.aggression >> 10
expect:
m.getAggression() == 10 // This works
and:
m.aggression == 10 // This fails! m.aggression is null!
}
}
What on Earth is going on? The problem goes away if I make Entity concrete, but then of course I can't hydrate any Monster objects since Hibernate doesn't know what to do with Entity (and I don't want to make Entity a domain object, though I suppose I will if I really must).
What am I missing?
The problem is GORM expects the super class to be a domain class.
With Groovy 2.0, which is what Grails 2.2.4 has, you can use compile-time mixins to add methods to a class. This allows for method reuse without inheritance.
The Entity can remain as not a domain class, but it must be a concrete class. Then, instead of subclassing, use it as a mixin.
#Mixin(Entity)
class RefactoredMonster {
int aggression
}
An alternative
Since you need the ability to override methods, as you said, Mixins are out.
Looking at this from a higher level, a potential issue is the architecture/design. Inheritance is meant to represent is-a relationships (ex. a Dog is an Animal). But when inheritance is used primarily as a way to reuse methods, it can lead to... a mess.
It may be better to forgo inheritance and choose has-a (delegation) instead. This would allow you to reuse behaviour and override it when needed. Unfortunately, Groovy 2.0 doesn't support #Delegate. So the following example is going to have more boilerplate code than the same thing coded in Groovy 2.4 would:
interface Flier {
def fly();
}
class FlierImp {
def fly() { "I'm fying! WOOT!" }
}
class RealDuck implements Flier {
def flier
RealDuck() {
flier = new FlierImp() // Purposely not using injection
}
def fly() {
flier.fly()
}
}
class RubberDuck implements Flier {
def fly() { "I don't fly" }
}
def duck = new RealDuck()
def rubberDuck = new RubberDuck()
assert duck.fly() == "I'm fying! WOOT!"
assert rubberDuck.fly() == "I don't fly"
In the example above RealDuck and RubberDuck represent domain classes (which is why I'm not injecting the flier). The flying behaviour is demanded by an interface and implemented either via a class which only implements the behaviour (FlierImp), or by implementing it directly, as shown in RubberDuck.

Mock method on a Mock Object in Spock

I have the following class which i am trying to mock using spock:
final class A{
private B b
public getB(){
return b
}
public A(B b){
this.b = b
}
}
and I tried to mock this class using following code and it is working.
def "test"(){
def mockA = GroovyMock(A)
when:
service.x()
then:
1 * new A(*_) >> {mockA}
}
Below is my x() method:
x(){
A a = new A(b)
B b = a.getB()
}
Now I want to mock a.getB() to get a mock object for B. I tried to create a mock for B but I am getting null at a.getB(). Is it possible to mock the getB() method to get a mock Object for B?
So I want to do some thing like
1 * a.getB() >> {mockB}
but I am getting null exception
do
def mockA = GroovyMock(A) >> {
getB() >> GroovyMock(B)
}.
P.S. I am surprised mocking a constructor of A works without specifying global: true

GORM bidirectional One-to-Many

I'm trying to create a bidirectional one-to-many relationship between Foo and Bar domains in GORM.
Here's what I have so far:
class Bar {
static belongsTo = [foo: Foo]
}
class Foo {
Set bars = []
static hasMany = [bars: Bar]
}
The problem that I'm having is when I go to use the relationship methods, they don't seem to behave the way that I think they should. For example, you would think a statement like "foo.bars.add(bar)" would also set the foo field on the bar argument. But when I call "bar.foo.id" I'm told that the foo field is null. I can fix that problem if I use "bar.foo = foo" instead of "foo.bars.add(bar)". Unfortunately, when I call "foo.bars.size()" it tells me that it is 0.
To get a clearer picture of what I'm talking about, here are my tests:
def testFoo() {
def foo = new Foo()
def bar = new Bar()
foo.bars.add(bar)
println "foo.bars.size() = ${foo.bars.size()}"
println "bar.id = ${bar.id}"
for(def xbar : foo.bars) {
println "bar.id = ${xbar.id}"
}
println "foo.id = ${foo.id}"
println "bar.foo.id = ${bar?.foo?.id}" // <- is null
}
def testBar() {
def foo = new Foo()
def bar = new Bar()
bar.foo = foo
println "foo.bars.size() = ${foo.bars.size()}" // <- is 0
println "bar.id = ${bar.id}"
for(def xbar : foo.bars) {
println "bar.id = ${xbar.id}"
}
println "foo.id = ${foo.id}"
println "bar.foo.id = ${bar?.foo?.id}"
}
What am I doing wrong?
Note: I'm running this through an integration test. I've also found that "foo.addToBars(bar)" works the way that I think "foo.bars.add(bar)" and "bar.foo = foo" should work.
Update Here's a quick hack I did that does what I want (using Hibernate and JPA):
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import stuff.Foo;
public class MyList<Bar> extends LinkedList {
private Foo foo;
public MyList(Foo foo) {
this.foo = foo;
}
#Override
public boolean add(Object obj) {
boolean result = super.add(obj);
try {
Method barMethod = obj.getClass().getDeclaredMethod("setFoo", Foo.class);
barMethod.invoke(obj, foo);
}
catch(NoSuchMethodException noSuchMethod) {
noSuchMethod.printStackTrace();
}
catch(InvocationTargetException invocationTarget) {
invocationTarget.printStackTrace();
}
catch(IllegalAccessException illegalAccess) {
illegalAccess.printStackTrace();
}
return result;
}
}
If you read the documentation, you'll learn that, as you found out but are still questioning, the correct way to add items to a collection so they are persisted correctly is to use the addTo* methods.
So in your case, when you said that using addToBars worked, that's the right way to do this. That said, there are some performance hits you take with that. Another way is to do:
bar.foo = foo
bar.save()
The downside is that foo will not contain bar in its existing Set. You'd have to pull it from the database again. It's a bit of a give and take and you just use the best method for your situation.

Better way to discover relationship dynamically when saving a new record? (otherSide fails)

Given this relationship:
class A {
String name
static hasMany = [b:B]
}
class B {
String name
static belongsTo = [a:A]
}
I have an record b that I want to save. I've already discovered via working Grails reflection (omitted in the code example below) that it needs to be an instance of class B. Beyond that, record b only knows:
it has a relation "a"
relation "a"'s key
Since it's a dynamic case, we do not know and must discover:
relation "a" is to an instance of class A (so we can call A.find(a's key))
the "other side" of the relation - class A's perspective - is relation "b" (so we can call .addToB(b))
So how do I save b to the database? Here's how I'm doing it:
class AssocTests extends GrailsUnitTestCase {
protected void setUp() {
super.setUp()
// I don't know this part, but it's in the DB
def a = new A(name:"al")
a.save()
}
void testAssociation() {
// I want to create a new B such that name="bob"
// I also had to discover "class B" using (working) Grails reflection
// but omitted it for this example.
def b = new B(name:"bob")
// ... and the relation is as "given" below
def given = [a:[name:"al"]]
// So I need to call A.find([name:"al"]).addToB(b). But "A" and
// "addToB" are unknown so need to be found via reflection
def gdc = new DefaultGrailsDomainClass(B)
given.each { give ->
def prop = gdc.getPropertyByName(give.key)
if (prop.isAssociation() && !prop.isOwningSide()) {
println "I want to use otherSide, but it's ${prop.otherSide}"
def os = reallyGetOtherSide(B, give)
def object = os.parent.find(
os.parent.newInstance(give.value))
object."${os.method}"(b)
}
}
def bFound = B.findByName("bob")
assertEquals "al", bFound.a.name
}
def reallyGetOtherSide(clazz, relation) {
def parent=clazz.belongsTo[relation.key]
def addTo=parent.hasMany.find { (clazz == it.value) }.key
[parent:parent, method:"addTo${addTo.capitalize()}"]
}
}
...with otherSide returning null, unfortunately. This can't be the best way to do this, can it?
If I understood you correctly, You can refer to these docs here. You can try the following:
`new A(name:"Gatwick")
.addToB(new B(name:"BA3430"))
.addToB(new B(name:"EZ0938"))
.save()`

Resources