Is object deep-compare possible with Spock Framework? - groovy

How do I check for deep object equality with spock.
Lets say we have a super simple test that compares to identical person objects
def "A persons test"() {
setup:
def person1 = new Person("Foo", new Address("Bar"))
def person2 = new Person("Foo", new Address("Bar"))
expect:
person1 == person2
}
The test fails
Condition not satisfied:
person1 == person2
| | |
| | Person#6bedbc4d
| false
Person#57af006c
This looks like a very natural way of asserting equality.
One of the main reason to start using spock was to avoid having to write a lot of hamcrest boilerplate matchers code.

Spock has no built-in mechanism for performing deep Object comparison, because defining object equality is out of scope of any testing framework. You can do a various things.
1. Both classes are Groovy classes
If both your classes (Person and Address) are Groovy classes you can generate equals and hashCode methods using #EqualsAndHashCode annotation over both classes, like:
import groovy.transform.EqualsAndHashCode
import groovy.transform.TupleConstructor
import spock.lang.Specification
class PersonSpec extends Specification {
def "a person test"() {
setup:
def person1 = new Person("Foo", new Address("Bar"))
def person2 = new Person("Foo", new Address("Bar"))
expect:
person1 == person2
}
#TupleConstructor
#EqualsAndHashCode
static class Person {
String name
Address address
}
#TupleConstructor
#EqualsAndHashCode
static class Address {
String city
}
}
This is just a convenient alternative for implementing both methods in Groovy.
2. Both classes are Java classes
If you want to compare both objects with == operator then you will have to define equals and hashCode methods in both classes, something like:
public final class Person {
private final String name;
private final Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public Address getAddress() {
return address;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (name != null ? !name.equals(person.name) : person.name != null) return false;
return address != null ? address.equals(person.address) : person.address == null;
}
#Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (address != null ? address.hashCode() : 0);
return result;
}
static class Address {
private final String city;
public Address(String city) {
this.city = city;
}
public String getCity() {
return city;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Address address = (Address) o;
return city != null ? city.equals(address.city) : address.city == null;
}
#Override
public int hashCode() {
return city != null ? city.hashCode() : 0;
}
}
}
In this example both methods were defined using IntelliJ IDEA "Generate equals and hashCode" command.
3. I can use Lombok!
If you don't want to define both methods manually (because e.g. you have to remember to change them anytime you modify your class fields) then you can use Lombok's #EqualsAndHashCode annotation that does something similar to Groovy's annotation, but can be applied to any Java class.
4. I want to keep default equals and hashCode methods
Well, in this case you can try various things:
You can try comparing both objects field-by-field, like:
class PersonSpec extends Specification {
def "a person test"() {
setup:
def person1 = new Person("Foo", new Address("Bar"))
def person2 = new Person("Foo", new Address("Bar"))
expect:
person1.name == person2.name
and:
person1.address.city == person2.address.city
}
#TupleConstructor
static class Person {
String name
Address address
}
#TupleConstructor
static class Address {
String city
}
}
You can try using 3rd party tools like Unitils reflection assertion
That may sound bizarre, but you can compare JSON representation of both objects, something like:
import groovy.json.JsonOutput
import groovy.transform.TupleConstructor
import spock.lang.Specification
class PersonSpec extends Specification {
def "a person test"() {
setup:
def person1 = new Person("Foo", new Address("Bar"))
def person2 = new Person("Foo", new Address("Bar"))
expect:
new JsonOutput().toJson(person1) == new JsonOutput().toJson(person2)
}
#TupleConstructor
static class Person {
String name
Address address
}
#TupleConstructor
static class Address {
String city
}
}
Anyway, I would definitely suggest defining equals and hashCode in one way or another and simply use == operator. Hope it helps.

You can take advantage of Groovy's succinct map comparison syntax:
person1.properties == person2.properties
That only works for simple flat objects, not nested ones. You could adapt it like so:
person1.properties << ['address': person1.address.properties] == person2.properties << ['address': person2.address.properties]
...but JSON solution is more elegant at that point.

It seems, that you need to correct override your equals and hashcode methods.
In Groovy it can be done really easily, you need to use #Canonical annotation. It gives you more than equals and hashcode, buy the way.

I highly recommend you use Assertj for deep assertions. See below an example:
def "labels1 should be deeply equal to labels2"() {
when:
def labels1 = [new Label("labelA"), new Label("labelB")]
def labels2 = [new Label("labelB"), new Label("labelA")]
then:
assertThat(labels1)
.usingRecursiveComparison()
.ignoringCollectionOrder()
.isEqualTo(labels2)
}
Don't forget to add the Gradle dependency:
dependencies {
testImplementation "org.assertj:assertj-core:3.11.1"
}

Related

What is the static version of propertyMissing method in Groovy?

ok - tried looking /reading and not sure i have an answer to this.
I have a Utility class which wraps a static ConcurrentLinkedQueue internally.
The utility class itself adds some static methods - i dont expect to call new to create an instance of the Utility.
I want to intercept the getProperty calls the utility class - and implement these internally in the class definition
I can achieve this by adding the following to the utility classes metaclass, before i use it
UnitOfMeasure.metaClass.static.propertyMissing = {name -> println "accessed prop called $name"}
println UnitOfMeasure.'Each'
however what i want to do is declare the interception in the class definition itself. i tried this in the class definition - but it never seems to get called
static def propertyMissing (receiver, String propName) {
println "prop $propName, saught"
}
i also tried
static def getProperty (String prop) { println "accessed $prop"}
but this isnt called either.
So other than adding to metaClass in my code/script before i use, how can declare the in the utility class that want to capture property accesses
the actual class i have looks like this at present
class UnitOfMeasure {
static ConcurrentLinkedQueue UoMList = new ConcurrentLinkedQueue(["Each", "Per Month", "Days", "Months", "Years", "Hours", "Minutes", "Seconds" ])
String uom
UnitOfMeasure () {
if (!UoMList.contains(this) )
UoMList << this
}
static list () {
UoMList.toArray()
}
static getAt (index) {
def value = null
if (index in 0..(UoMList.size() -1))
value = UoMList[index]
else if (index instanceof String) {
Closure matchClosure = {it.toUpperCase().contains(index.toUpperCase())}
def position = UoMList.findIndexOf (matchClosure)
if (position != -1)
value = UoMList[position]
}
value
}
static def propertyMissing (receiver, String propName) {
println "prop $propName, saught"
}
//expects either a String or your own closure, with String will do case insensitive find
static find (match) {
Closure matchClosure
if (match instanceof Closure)
matchClosure = match
if (match instanceof String) {
matchClosure = {it.toUpperCase().contains(match.toUpperCase())}
}
def inlist = UoMList.find (matchClosure)
}
static findWithIndex (match) {
Closure matchClosure
if (match instanceof Closure)
matchClosure = match
else if (match instanceof String) {
matchClosure = {it.toUpperCase().contains(match.toUpperCase())}
}
def position = UoMList.findIndexOf (matchClosure)
position != -1 ? [UoMList[position], position] : ["Not In List", -1]
}
}
i'd appreciate the secret of doing this for a static utility class rather than instance level property interception, and doing it in class declaration - not by adding to metaClass before i make the calls.
just so you can see the actual class, and script that calls - i've attached these below
my script thats calling the class looks like this
println UnitOfMeasure.list()
def (uom, position) = UnitOfMeasure.findWithIndex ("Day")
println "$uom at postition $position"
// works UnitOfMeasure.metaClass.static.propertyMissing = {name -> println "accessed prop called $name"}
println UnitOfMeasure[4]
println UnitOfMeasure.'Per'
which errors like this
[Each, Per Month, Days, Months, Years, Hours, Minutes, Seconds]
Days at postition 2
Years
Caught: groovy.lang.MissingPropertyException: No such property: Per for class: com.softwood.portfolio.UnitOfMeasure
Possible solutions: uom
groovy.lang.MissingPropertyException: No such property: Per for class: com.softwood.portfolio.UnitOfMeasure
Possible solutions: uom
at com.softwood.scripts.UoMTest.run(UoMTest.groovy:12)
Static version of propertyMissing method is called $static_propertyMissing:
static def $static_propertyMissing(String name) {
// do something
}
This method gets invoked by MetaClassImpl at line 1002:
protected static final String STATIC_METHOD_MISSING = "$static_methodMissing";
protected static final String STATIC_PROPERTY_MISSING = "$static_propertyMissing";
// ...
protected Object invokeStaticMissingProperty(Object instance, String propertyName, Object optionalValue, boolean isGetter) {
MetaClass mc = instance instanceof Class ? registry.getMetaClass((Class) instance) : this;
if (isGetter) {
MetaMethod propertyMissing = mc.getMetaMethod(STATIC_PROPERTY_MISSING, GETTER_MISSING_ARGS);
if (propertyMissing != null) {
return propertyMissing.invoke(instance, new Object[]{propertyName});
}
} else {
// .....
}
// ....
}
Example:
class Hello {
static def $static_propertyMissing(String name) {
println "Hello, $name!"
}
}
Hello.World
Output:
Hello, World!

Spock Mock not working for unit test

I am getting weird results from a Spock unit test that I thought was being caused by a misuse of Groovy's TupleConstructor annotation. However, thanks to the help of another user, I see it is a problem with the way Spock is creating mocks. Although I have fixed the issue by replacing the injected mocks with real instances, I need to in fact get mocks working here.
My main classes:
#Canonical
#TupleConstructor(callSuper = true)
abstract class Vehicle {
Long id
}
#Canonical
#TupleConstructor(callSuper = true, includeSuperProperties = true)
abstract class Foobaz extends Vehicle {
String name
String label
String description
}
#Canonical
#TupleConstructor(callSuper = true, includeSuperProperties = true)
class Fizz extends Foobaz {
// This is an empty class that creates a meaningful name over the
// abstract Foobaz parent class. This may seem like bad design in
// this analogy, but I assure you it makes sense (from a Domain-Driven
// Design perspective) in my actual application.
}
#Canonical
#TupleConstructor(callSuper = true, includeSuperProperties = true)
class Car extends Vehicle {
Fizz fizz1
Fizz fizz2
#Override
String toString() {
"${fizz1.name} - ${fizz2.name}"
}
}
My Spock test:
class CarSpec extends Specification {
def "toString() generates a correct string"() {
given: "a Car with some mocked dependencies"
String f1 = 'fizzy'
String f2 = 'buzzy'
Fizz fizz1 = Mock(Fizz)
Fizz fizz2 = Mock(Fizz)
fizz1.name >> f1
fizz2.name >> f2
Car car = new Car(1L, fizz1, fizz2)
when: "we call toString()"
String str = car.toString()
then: "we get a correctly formatted string"
"${f1} - ${f2}" == str
}
}
But when I run this I get the following failure/error:
Condition not satisfied:
"${f1} - ${f2}" == str
| | | |
fizzy buzzy | null - null
false
<omitting details here for brevity>
Expected :null - null
Actual :fizzy - buzzy
Any ideas where I'm going awry?
If you change your specification to this:
class CarSpec extends Specification {
def "toString() generates a correct string"() {
given: "a Car with some mocked dependencies"
String f1 = 'fizzy'
String f2 = 'buzzy'
Fizz fizz1 = Mock()
Fizz fizz2 = Mock()
Car car = new Car(1L, fizz1, fizz2)
when: "we call toString()"
String str = car.toString()
then: "we get a correctly formatted string + getProperty('name') is called once on each Mock"
"$f1 - $f2" == str
1 * fizz1.getProperty('name') >> f1
1 * fizz2.getProperty('name') >> f2
}
}
So you define the interactions in the then block, then it should all work fine...
From our discussion on a different one of #smeeb's questions, I looked into this a bit more since I was very confused why this wasn't working.
I created my own test.
class SomeTest extends Specification {
static class Driver {
String getName(Superclass superclass) {
return superclass.name
}
}
static abstract class Superclass {
String name
}
static class Subclass extends Superclass {
}
def 'test'() {
given:
def driver = new Driver()
def subclass = Mock(Subclass)
subclass.name >> 'test'
expect:
driver.getName(subclass) == 'test'
}
}
It failed with the same problem that #smeeb saw.
driver.getName(subclass) == 'test'
| | | |
| null | false
| Mock for type 'Subclass' named 'subclass'
I tried changing a few different things and found that when I either removed the abstract modifier from Superclass or changed the return superclass.name to return superclass.getName() the test began working.
It seems there is a weird interaction on the Groovy-level between getting inherited public fields from an abstract superclass using the auto-generated accessors.
So, in your case either remove abstract modifier from FooBaz, or change your code to:
#Override
String toString() {
"${fizz1.getName()} - ${fizz2.getName()}"
}

Groovy override constructor named parameters

Giving class
class A {
def String name = ''
def String lower = ''
}
Constructor with named parameters can be used
new A(name: 'Alice', lower: 'alice')
I don't want to specify lower parameter as it is always equals to name.toLowerCase()
How to implement this constructor?
So after calling:
def a = new A(name: 'Alice')
println "${a.lower}"
alice will be printed
i am not sure, what you are really after here. if you really need some magic only for the ctor, let us know. but the most common ways to solve this, would either be:
calculate the lower, when it's needed
String getLower() { name.toLowerCase() }
override the setter of name
class A {
String name = ''
private String lower = ''
void setName(String name) {
this.name = name
this.lower = name?.toLowerCase()
}
String getLower() { lower }
}
def a = new A(name: 'Charlie')
assert a.lower == 'charlie'

groovy generic fluent builder

I'd like to create a simple wrapper, which would allow calling objects methods as a fluent interface. I've been thinking about rewriting methods of a class upon creation, but this doesn't seem to work. Is this possible in some way with groovy metaprograming?
I have this kind of code snippet so far:
class FluentWrapper {
def delegate
FluentWrapper(wrapped) {
delegate = wrapped
delegate.class.getMethods().each { method ->
def name = method.getName()
FluentWrapper.metaClass."$name" = { Object[] varArgs ->
method.invoke(wrapped, name, varArgs)
return this
}
}
}
def methodMissing(String name, args) {
def method = delegate.getClass().getDeclaredMethods().find { it.match(name) }
if(method) {
method.invoke(delegate,name, args)
return FluentWrapper(delegate)
}
else throw new MissingMethodException(name, delegate, args)
}
}
Assuming example Java class:
class Person {
void setAge()
void setName()
}
I'd like to be able to execute the following piece of code:
def wrappedPerson = new FluentWrapper(new Person())
wrappedPerson.setAge().setName()
I'm using Groovy 1.6.7 for this.
This is all Groovy, and I'm using 1.8.6 (the current latest), but given this Person Class:
class Person {
int age
String name
public void setAge( int age ) { this.age = age }
public void setName( String name ) { this.name = name }
public String toString() { "$name $age" }
}
And this FluentWrapper class:
class FluentWrapper {
def delegate
FluentWrapper(wrapped) {
delegate = wrapped
}
def methodMissing(String name, args) {
def method = delegate.getClass().declaredMethods.find { it.name == name }
if(method) {
method.invoke( delegate, args )
return this
}
else throw new MissingMethodException(name, delegate, args)
}
}
Then, you should be able to do:
def wrappedPerson = new FluentWrapper(new Person())
Person person = wrappedPerson.setAge( 85 ).setName( 'tim' ).delegate
And person should have the age and name specified
I find #tim_yates' answer nice, but you couldn't access delegate methods' return values (something one usually likes doing, even for Builders in the case of build() :)
Moreover, if this wasn't intended for a Builder but for an object with a chainable interface (like that of jQuery wrapped objects in JS), it would be a serious issue.
So I'd put the wrapper like this:
class FluentWrapper {
def delegate
FluentWrapper(wrapped) {
delegate = wrapped
}
def methodMissing(String name, args) {
def method = delegate.getClass().declaredMethods.find { it.name == name }
if(method) {
def result = method.invoke(delegate, args)
return result != null ? result : this
}
else throw new MissingMethodException(name, delegate, args)
}
}
Note the elvis operator is unsuitable since a falsy value would never get returned.
Of course, it's up to the invoker to know wether a method is chainable or not, but that could be overcome with method annotations if neccesary.

EF Code First - Include(x => x.Properties.Entity) a 1 : Many association

Given a EF-Code First CTP5 entity layout like:
public class Person { ... }
which has a collection of:
public class Address { ... }
which has a single association of:
public class Mailbox { ... }
I want to do:
PersonQuery.Include(x => x.Addresses).Include("Addresses.Mailbox")
WITHOUT using a magic string. I want to do it using a lambda expression.
I am aware what I typed above will compile and will bring back all Persons matching the search criteria with their addresses and each addresses' mailbox eager loaded, but it's in a string which irritates me.
How do I do it without a string?
Thanks Stack!
For that you can use the Select method:
PersonQuery.Include(x => x.Addresses.Select(a => a.Mailbox));
You can find other examples in here and here.
For any one thats still looking for a solution to this, the Lambda includes is part of EF 4+ and it is in the System.Data.Entity namespace; examples here
http://romiller.com/2010/07/14/ef-ctp4-tips-tricks-include-with-lambda/
It is described in this post: http://www.thomaslevesque.com/2010/10/03/entity-framework-using-include-with-lambda-expressions/
Edit (By Asker for readability):
The part you are looking for is below:
public static class ObjectQueryExtensions
{
public static ObjectQuery<T> Include<T>(this ObjectQuery<T> query, Expression<Func<T, object>> selector)
{
string path = new PropertyPathVisitor().GetPropertyPath(selector);
return query.Include(path);
}
class PropertyPathVisitor : ExpressionVisitor
{
private Stack<string> _stack;
public string GetPropertyPath(Expression expression)
{
_stack = new Stack<string>();
Visit(expression);
return _stack
.Aggregate(
new StringBuilder(),
(sb, name) =>
(sb.Length > 0 ? sb.Append(".") : sb).Append(name))
.ToString();
}
protected override Expression VisitMember(MemberExpression expression)
{
if (_stack != null)
_stack.Push(expression.Member.Name);
return base.VisitMember(expression);
}
protected override Expression VisitMethodCall(MethodCallExpression expression)
{
if (IsLinqOperator(expression.Method))
{
for (int i = 1; i < expression.Arguments.Count; i++)
{
Visit(expression.Arguments[i]);
}
Visit(expression.Arguments[0]);
return expression;
}
return base.VisitMethodCall(expression);
}
private static bool IsLinqOperator(MethodInfo method)
{
if (method.DeclaringType != typeof(Queryable) && method.DeclaringType != typeof(Enumerable))
return false;
return Attribute.GetCustomAttribute(method, typeof(ExtensionAttribute)) != null;
}
}
}

Resources