I'm working in migrating a large application from Grails 3.3 to Grails 4.
On of the issues we got is related to Spock, the functionality we used in Grails 3.39 seems to be missing: whe using a datatable to represent the specs, the column for the inputs, seems to be accepting jus integers values
In the below code just the first line of the specks is passing the text. No the next two, as the spock is transforming to integer befor passing it to Math.round(value)
import spock.lang.*
#Unroll
void 'test to demostrate Spock is just accepting integer in datatable column value'() {
expect:
Math.round(value) == result
where:
value | result
1234 | 1234
4321.56d | 4322d
1111.56f | 1112d
}
I was noty getting this issue in version 3.3 of Grails.
Thanks in advance for attend this issue
Juan
UPDATE:
UPDATE:
The change of behavior described, actually occurs when the test based on datatable is preceded by a test that includes throwing an excetion
WORK AROUND:
Move the test that includes the exception throwing to be the last test.
Grails 4 uses org.spockframework:spock-core:1.2-groovy-2.5 and in this version it works as expected (as in other versions of Spock).
Update your specification in this way:
import spock.lang.Specification
import spock.lang.Unroll
class RoundSpec extends Specification {
#Unroll
void 'Math.round(#value) == #result'() {
setup:
println "$value as ${value.class}"
expect:
Math.round(value) == result
where:
value || result
1234 || 1234
4321.56d || 4322
1111.56f || 1112
}
}
Then you can see that all test cases pass the test and you can also see in the output what data of which class is passed into the test:
So Integer, Double and Float are passed and not Integer in all cases as you write.
What I can see in your test is, that you have result value as a Double two times, but Math.round() returns long each time.
Related
I have a domain class with a float field:
class DvQuantity {
float magnitude
String units
}
When I have this:
new DvQuantity( magnitude: '11.0', units: 'm' ).save()
In the database I see: magnitude = 110.0 instead of 11.0
Is this a Grails bug? Is there any workaround?
It is not a bug. As stated in the comment, parsing of numbers depends on your locale. See example below:
import java.text.NumberFormat
String a = '11,0'
assert NumberFormat.getInstance(Locale.US).parse(a).floatValue() == 110
assert NumberFormat.getInstance(Locale.FRANCE).parse(a).floatValue() == 11.0
There are many different ways to change your default number format - for example PropertyEditorRegistrar or ValueConverter. You can also enforce format on the view using validators.
Here Grails databinding with decimal delimiter is answer with example code how to do that for Grails <2.3 and >=2.4
I'm newbie to fitnesse and trying to run a simple calculator class which has "add" method accepting 2 parameters and returning the result. Can anyone help me to write the firnesse code for this, my method is as below
public int add(int a, int b) {
return a+b;
}
I believe you are trying to get a table like:
|AddFixtureTest |
|left|right|sum?|
|1 |1 |2 |
|2 |4 |6 |
This requires a java class like:
import fit.ColumnFixture;
public class AddFixtureTest extends ColumnFixture {
public int left;
public int right;
public int sum(){
return add(left, right);
}
private int add(int a, int b) {
return a+b;
}
}
See http://fitnesse.org/FitNesse.UserGuide.FixtureGallery.BasicFitFixtures.ColumnFixture
I assume Slim is fine by you and I'm gonna use script table for this (more out of habit):
|script| <class name> |
|add;| <variable1> | <variable2> |
As simple as that. And, make sure you are using the right libraries and pointing to the location of the where the class file is.
Example:
|import|
fitnesse.slim.test |
If you are interested in knowing why I have placed a semi-colon after "add", and how script table works, please go through this:
http://www.fitnesse.org/FitNesse.UserGuide.WritingAcceptanceTests.SliM.ScriptTable
You can get the FitNesse tutorial there for .Net code. I tried to describe how to use FitNesse for different types of testing.
If you want to check two parameters on the output you can do the following:
Return IEnumerable implementation with classes, which contains get
and set properties (see here). NetRunner will use get properties
if it can, otherwise it will use set properties. As a result, it will
set all available data first and then compare items left.
You can use out parameters in the tests, so you can return several different values and check them
The correct answer is:
|script:<classPackage>.<ClassName>|
|check|add;|8|8|16|
First tell the script to navigate to the correct class. In the next line you have to call either a method or a constructor. You can call the method by it's name (or fancy smansy digibetic words that vaguely match) and tack on a semicolon. But anything put into the pipe-blocks after that will be interpreted as parameters for that method. So how do you put the expected output?
The trick is to tell the FitNesse engine you need a result, with the keyword 'check'.
This will make the final pipe-block be the field for the expected result, in this case 16.
Here is a picture of the java code
Here is a picture of the text input and the FitNesse sceen result
I have a "domain"(model) that want to do an Unity Test to check if works.
But when I execute the test I get
java.lang.IllegalArgumentException: Test class can only have one constructor
Thats always happen when trying to initialize a class of some domain(model).
What would be the approach to do correctly the testcase?
class Race {
static constraints = { }
String name
Date startDate
String city
String state
BigDecimal distance
BigDecimal cost
Integer maxRunners = 100000
BigDecimal inMiles() {
return 0.6
}
}
And in the Unity Test Class
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(Race)
class RaceTest extends Specification {
void testInMiles() {
when:
def model = new Race(distance:5.0);
then:
0.6 == model.inMiles()
}
}
In Grails 2.4.x (which is what I'm assuming you're using) the default test type is a Spock test, and that's what's created by the generate-* scripts. You can still write your own tests in JUnit 3 or 4 style if you prefer. But test classes in Spock (at least using the Grails integration, I'm not sure if it's as strict outside of Grails) have to have names ending in "Spec". That's why you're seeing that error.
Test methods do not have to be void and start with "test" (JUnit 3 style) or be void and have an #Test annotation (JUnit 4 style). The test runner decides if a method is a test method if it's public (either explicitly or if there's no scope modifier) and there's at least one labelled block, e.g. when:, given:, then:, etc. Further, Spock uses some AST magic to allow you to use spaces in method names (you just have to quote the whole name) and have expressive, self-descriptive method names, e.g.
def 'an admin without ROLE_SUPER cannot view records of other admins'() {
...
}
In a controller I have this finder
User.findByEmail('test#test.com')
And works.
Works even if I write
User.findByEmail(null)
But if i write
User.findByEmail(session.email)
and session.email is not defined (ergo is null) it throw exception
groovy.lang.MissingMethodException: No signature of method: myapp.User.findByEmail() is applicable for argument types: () values: []
Is this behavior right?
If i evaluate "session.email" it give me null so I think it must work as it do when I write
User.findByEmail(null)
Even more strange....
If I run this code in groovy console:
import myapp.User
User.findByEmail(null)
It return a user that has null email but if I run the same code a second time it return
groovy.lang.MissingMethodException: No signature of method: myapp.User.findByEmail() is applicable for argument types: () values: []
You can't use standard findBySomething dynamic finders to search for null values, you need to use the findBySomethingIsNull version instead. Try
def user = (session.email ? User.findByEmail(session.email)
: User.findByEmailIsNull())
Note that even if User.findByEmail(null) worked correctly every time, it would not necessarily give you the correct results on all databases as a findBySomething(null) would translate to
WHERE something = null
in the underlying SQL query, and according to the SQL spec null is not equal to anything else (not even to null). You have to use something is null in SQL to match null values, which is what findBySomethingIsNull() translates to.
You could write a static utility method in the User class to gather this check into one place
public static User byOptEmail(val) {
if(val == null) {
return User.findByEmailIsNull()
}
User.findByEmail(val)
}
and then use User.byOptEmail(session.email) in your controllers.
Jeff Brown from grails nabble forum has identified my problem. It's a GORM bug. see jira
More info on this thread
This jira too
I tried with debugger and it looks it should be working, as you write. Maybe the groovy itself is a little bit confused here, try to help it this way:
User.findByEmail( session['email'] )
I executed a simple test case (on jobss-ejb environment), which compares/asserts 2 strings. Unfortunately, the strings are not matching to each other (there's a bug).
But the problem is, when I execute the test case from eclipse it logs the result as failure which is correct because there's a mismatch between expected and actual objects;
whereas when I execute the same test case from ant, the result is logged as error.
This is really strange and surprising and to add more to it, this behaviour is noticed on junit 4 version only, when i execute the test case on junit 3.8, both ant and eclipse log the result as failure.
Any suggestion or pointers on what might be going wrong?
Thanks in advance :)
Ant-version: 1.6.1
Junit version: 4.10
Ok, i digged down further and found that this is not related to any specific application server. It can be reproduced on any app server.
Just create a sample (junit4) test case as mentioned below:
#Test
public void stringTest() {
org.junit.Assert.assertEquals("Comparing 2 string:", "abc", "xyz");
}
Now, run it from eclipse; you will see result as 1 failure.
Run the same via some app server, using an ant (or maven) target and you will get the result as error.
After going through the logs I think that this must be because the junit4 org.junit.Assert.assertEquals(String message, Object expected,Object actual) method throws ComparisonFailure instead of AssertionError.
My analysis on this is that junit4 assert() method (org.junit.Assert.assertEquals(String, Object, Object)) throws ComparisonFailure only for String instances.
Following is the code of org.junit.Assert.assertEquals (junit4 assert method):
static public void assertEquals(String message, Object expected, Object actual) {
if (expected == null && actual == null)
return;
if (expected != null && isEquals(expected, actual))
return;
else if (expected instanceof String && actual instanceof String) {
String cleanMessage= message == null ? "" : message;
throw new ComparisonFailure(cleanMessage, (String) expected,
(String) actual);
} else
failNotEquals(message, expected, actual);
}
And this is the code for junit.framework.Assert.assertEquals(String, Object, Object) (i.e. junit3 assert method)
static public void assertEquals(String message, Object expected, Object actual) {
if (expected == null && actual == null)
return;
if (expected != null && expected.equals(actual))
return;
failNotEquals(message, expected, actual);
}
It can be observed that in junit4 assertEquals() an extra check is added for unequal String instances which throws ComparisonFailure for two unequal strings. For all other unequal objects i.e Integer, Long,etc. the call goes to failNotEquals() method which throws an AssertionError.
Can anyone help me to understand the design significance of adding a String instance check in junit4's org.junit.Assert.assertEquals() method. Why is it really added and why only for String?
The differences in test result behavior as mentioned in question is because of ant version issue. For lower versions of ant, you'll get such type of behavior (may be because the lower ant versions consider ComparisonFailure as error instead of failure).
I found this behavior in ant version 1.7.1 (and lower). But this issue is solved in latest ant jar i.e. 1.8.4.
When I executed the above mentioned test case on latest ant version, the result was logged as failure and not error.
So, if you encounter such a problem just update your ant jar to 1.8.4 or other latest version available.