I have my domain Class and my groovy class for unit test
class Product {
String product_code
String store
int price
String notes
//static hasOne = [description: Description]
static constraints = {
product_code blank:false, size: 1..15
price blank:false, scale: 2
store blank:false, size: 1..40
notes blank:true , size: 1..150
}
}
import org.apache.jasper.compiler.Node.ParamsAction;
import grails.test.mixin.*
import org.junit.*
import org.pricer.model.Product;
/**
* See the API for {#link grails.test.mixin.domain.DomainClassUnitTestMixin} for usage instructions
*/
#TestFor(Product)
class ProductTests {
void testSomething() {
if (Product.hasErrors()){
fail "not pass"
}else
assert "Pass"
}
}
when i try tu run test-app my ProductTest.testSomething i get
No signature of method: org.pricer.model.Product.hasErrors() is applicable for argument types: () values: []
Possible solutions: hasErrors(), getErrors(),
setErrors(org.springframework.validation.Errors), clearErrors(), hashCode()
groovy.lang.MissingMethodException: No signature of method: org.pricer.model.Product.hasErrors() is applicable for argument types: () values: []
Possible solutions: hasErrors(), getErrors(), setErrors(org.springframework.validation.Errors), clearErrors(), hashCode()
at
org.grails.datastore.gorm.GormStaticApi.methodMissing(GormStaticApi.groovy:97)
at org.pricer.ProductTests.testSomething(ProductTests.groovy:20)
You didn't instantiate domain class Product in your test. Try f.e.:
void testSomething() {
def product = new Product()
if (product.hasErrors()){
//do something
}
}
hasErrors() is an instance method. When you call Product.hasErrors() you're calling a class/static method, which in this case, does not exist.
So, as majkelo said, you need a Product instance first. But, you also need to trigger domain class validation so that if there are errors, hasErrors() will report them.
def product = new Product(product_code: 'ABC', store: 'StackOverflow', price: 1000000)
product.validate() /* You can also call product.save() to validate. */
if(product.hasErrors()) {
/* Do your thing */
}
A short-cut
You can combine validation and error checking like this:
if(product.validate()) {
/* validation passed. */
} else {
/* validation failed. */
}
Related
I am actually new in the world of Grails. I am trying to write a test case for domain class which is having some constraints . I am getting a Null pointer exception on my object when i am trying to run my unit test. On debugging I got to know that there is something fishy with my toString method which is causing the object to set as Null. How should I move ahead ? Any help is highly appreciated.
Here is my domain class:
#MultiTenant
class OrderCharge {
static scaffold = [
exclude: ['tenantId'],
]
static belongsTo = [
order: SalesOrder
]
MiscOrderCharges miscOrderCharges
Date lastUpdated
double quantity
double price
SapInvoiceRecord sapInvoice
static constraints = {
order(nullable: true)
quantity(min:1d)
miscOrderCharges()
sapInvoice(nullable: true)
}
String toString(){
def pattern = "\$##,###.00"
def currency = new DecimalFormat(pattern)
String rate = currency.format(miscOrderCharges.price)
return "$miscOrderCharges x$quantity"
}
}
Here is my Unit test case:
import grails.test.mixin.TestFor
import spock.lang.Unroll
import spock.lang.Specification
#TestFor(OrderCharge)
//#TestMixin(GroovyPageUnitTestMixin)
class ChargeSpec extends Specification {
def setup() {
mockForConstraintsTests(
OrderCharge, [
new OrderCharge(order: Mock(SalesOrder),
miscOrderCharges: Mock(MiscOrderCharges),
quantity: 1.0,
price:20.0
/*, sapInvoice: Mock(SapInvoiceRecord) */
)
]
)
}
void validateConstraints(obj, field, error) {
def validated = obj.validate()
if (error && error != 'valid') {
assert !validated
assert obj.errors[field]
assert error == obj.errors[field]
} else {
assert !obj.errors[field]
}
}
#Unroll("test inventory all constraints #field is #error")
def "test Charge all constraints"() {
given:
def obj = new OrderCharge("$field": val)
expect:
validateConstraints(obj, field, error)
where:
error |field |val
'nullable' |'orderCharge' |null
'nullable' |'sapInvoice' |null
'min' |'quantity' |-1
'min' |'price' |0
}
}
Thanks in advance.
The only thing that jumps out at me is your return in the toString().
return "$miscOrderCharges x$quantity"
You're using gStrings there. It's my understanding that individual variables can be referred to using simple $ notation, as in the format $somevariable, whereas expressions are in the format ${expression}.
In your statement x$quantity seems like a typo. Did you mean to multiply them as an expression like below?
return "${miscOrderCharges * quantity}"
See http://groovy.jmiguel.eu/groovy.codehaus.org/Strings+and+GString.html for more information.
The error was on integration test of a service. Yes, we're currently doing integration test on our service as a workaround since we cannot test the services via unit test due to userType mapping.
Regarding userType: Our Domain uses interface as properties. In addition findByinterface won't work on grails.
see below:
class Domain {
SomeProperty someProperty
String otherProperty
}
public interface SomeProperty {
//methods
}
enum Enum implements SomeProperty {
NAME,
OTHERNAME
//implementation of methods
}
class Domain can handle different kinds of enum implementing the SomeProperty inteface.
Database won't know what particular value should it saved so we go with the userType. below is the Domain with the mapping
class Domain {
SomeProperty someProperty
String otherProperty
}
static mapping = {
id generator: 'sequence', column: 'id', params: [sequence: 'domain_sequence']
someProperty type : userType, {
column name: "someProperty", sqlType: "varchar", length: 255
}
}
Updated:
Code being tested:
class ServiceBeingTested {
AnotherServiceInsideServiceBeingTested anotherServiceInsideServiceBeingTested //or def anotherServiceInsideServiceBeingTested
public void methodBeingTested(param1, param2, param3) {
Object object = privateMethod(..., ...) //private method contains no other service calls. just pure logic
anotherServiceInsideServiceBeingTested.voidMethod1(....)
anotherServiceInsideServiceBeingTested.voidMethod2(....)
}
}
My integration test:
class ServiceBeingTestedIntegrationSpec extends IntegrationSpec {
ServiceBeingTested serviceBeingTested = new ServiceBeingTested()
AnotherServiceInsideServiceBeingTested anotherServiceInsideServiceBeingTested
void setUp () {
anotherServiceInsideServiceBeingTested = Mock()
serviceBeingTested.anotherServiceInsideServiceBeingTested = anotherServiceInsideServiceBeingTested
}
void cleanup () {
//code here
}
void "methodBeingTested should invoke the 2 service method call"() {
given:
//initialize data here
//code
when:
serviceBeingTested.methodBeingTested(param1, param2, param3)
then:
1 * anotherServiceInsideServiceBeingTested.voidMethod1(....)
1 * anotherServiceInsideServiceBeingTested.voidMethod2(....)
}
}
StackTrace:
| Too few invocations for:
1 * anotherServiceInsideServiceBeingTested.voidMethod2(....) (0 invocations)
Unmatched invocations (ordered by similarity):
1 * anotherServiceInsideServiceBeingTested.this$3$voidMethod2(....)
The other service call with same anotherServiceInsideServiceBeingTested -i.e anotherServiceInsideServiceBeingTested.voidMethod1 was correctly invoked. I tried changing the parameters in test for voidMethod2 to wildcards but will still result to this error.
Thanks
In integration test cases, you don't need to mock any of the services as these are available by default as the full application is loaded.
Though, in unit test, you may use #TestFor annotation and specify the service which you want to test, this will inject a service variable which would be available through you specification / test class.
#TestFor(Service)
class ServiceBeingTestedIntegrationSpec extends Specification {
ServiceBeingTested serviceBeingTested = new ServiceBeingTested()
void setUp () {
serviceBeingTested.service = service
}
void cleanup () {
//code here
}
void "methodBeingTested should invoke the 2 service method call"() {
given:
//initialize data here
//code
when:
serviceBeingTested.methodBeingTested(param1, param2, param3)
then:
1 * service.voidMethod1(....)
1 * service.voidMethod2(....)
}
}
Also, in case above you could also try to stub your methods in setup after mocking these to avoid any other service called by your service which will throw NullPointerException and eventually your test would fail in case of unit tests.
example of stubbing could be:
1*service.voidMethod1 >> {
//some code setting up any data for you.
}
1*service.voidMethod2 >> {
//some code setting up any data for you.
}
If you use stubbing like above you can simply write down unit test cases as well.
I am new to Groovy & Grails. I am working on one of the sample one-to-many relationship in Grails.
The below is the code.
class User {
//properties
String login
String password
String role
//constraints and order of display of fields in UI
static constraints = {
login(blank: false, nullable: false, unique: true)
password(blank: false, nullable: false, password: true)
role(inList:["Admin", "Member"])
}
static hasMany = [posts : Post]
}
class Post {
String content
Date dateCreated
static constraints = {
content(blank: true)
}
static belongsTo = [user : User]
}
My Test class in Groovy
#TestFor(User)
class UserTests {
void testUserToPost() {
def user = new User(login: "joe", password: "joe", role:"Admin")
user.addToPosts(new Post(content: "First"));
user.addToPosts(new Post(content: "Second"));
user.addToPosts(new Post(content: "Third"));
user.save(flush: true)
assertEquals 3, User.get(user.id).posts.size()
}
}
While running the test class, getting following exception:
groovy.lang.MissingMethodException: No signature of method: com.library.forum.User.addToPosts() is applicable for argument types: (com.library.forum.Post) values: [com.library.forum.Post : (unsaved)]
Possible solutions: getPosts() at com.library.forum.UserTests.testUserToPost(UserTests.groovy:17)
Can anyone tell me where is the problem in code.
Since Grails 2.1.4, there's a change in mock behavior because of performance issue. So you need to mock all associated entities of the mocked entity.
See GRAILS-9637 - Due to a performance issue, #Mock no longer mocks
associated entities of the mocked entity. These have to be manually
specified. For example the following test will fail in 2.1.4 and
above:
#Mock(Author)
void testAddToBooks() {
def a = new Author()
a.addToBooks(new Book())
}
To correct the above test you need to mock both Author and Book:
#Mock([Author, Book])
void testAddToBooks() {
def a = new Author()
a.addToBooks(new Book())
}
You can check this reference.
You need to mock all related domain classes. Change :
#TestFor(User)
class UserTests {
to
#TestFor(User)
#Mock(Post)
class UserTests {
If you need, the mock annotation support a list of classes, for example: #Mock([Domain1, Domain2, Domain3])
I have a grails-plugin called "listadmin" there is a domain model "Liste":
package listadmin
class Liste {
String internal_name
String public_name
Boolean edtiable = true
Boolean visible = true
static hasMany = [eintrage : ListenEintrag]
static constraints = {
internal_name(unique : true , blank : false);
}
String toString() {
"${public_name}"
}
}
I have service called "SECO_ListenService" in the same module (grails-plugin):
package listadmin
class SECO_ListenService {
def getEntriesOfList(String intnalListName) {
def aList = Liste.findByInternal_name(intnalListName)
return aList
}
}
Now I try to call this service from an other module (grails-plugin) called "institutionadmin". The SECO_ListenService should return a list of strings for an select of a domain model in the inistitutionadmin:
package institutionadmin
import listadmin.SECO_ListenService
class Einrichtung {
Long einrichtungs_type
Long type_of_conzept
int anzahl_gruppen
int anzahl_kinder_pro_Gruppe
String offnungszeiten
static hasMany = [rooms : Raum]
static constraints = {
def aList = []
def sECO_ListenService = new SECO_ListenService()
aList=sECO_ListenService.getEntriesOfList("einrichtung_type")
einrichtungs_type(inList: aList)
}
}
If I try to run this application with the both modules. I get the following error:
Caused by MissingMethodException: No signature of method:
listadmin.Liste.methodMissing() is applicable for argument types: ()
values: []
It seemed to be that the service class don't know the "Liste"-domain-model. But I don't know where the error is. I also tried to call other standard methods like "findAll" but without any success.
Has anybody an idea where my mistake could be?
To get a service in a static context you need to access the grailsApplication spring bean. This can be done thought Holders. Example:
class MyService {
List<String> getAvailable() {
return ['A','B','C']
}
}
class MyDomainClass {
String something
static constraints = {
something inList: getSomethingList()
}
static List<String> getSomethingList() {
def myService = Holders.grailsApplication.mainContext.getBean('myService')
return myService.getAvailable()
}
}
I'm learning grails from Grails - getting started by Jason Rudolph book.
My domain class looks like that:
class Race {
String name;
Date startDateTime
String city
String state
Float distance
Float cost
Integer maxRunners = 10000
static hasMany = [registrations: Registration]
static constraints = {
name(maxSize: 50, blank: false)
startDateTime(validator: {
return it > new Date()
})
city(maxSize: 30, blank: false)
state(inList: ['GA', 'NC', 'SC', 'VA'], blank: false)
distance(min: 3.1f, max: 100f)
cost(min: 0f, max: 999.99f)
}
String toString() { "${this.name} : ${this.city}, ${this.state}" }
}
I want to test the custom validation of startDateTime field. Test looks like that:
class RaceTests extends GrailsUnitTestCase {
protected void setUp() {
super.setUp()
}
protected void tearDown() {
super.tearDown()
}
void testCustomDateValidation() {
def race = new Race()
race.startDateTime = null
assertFalse(race.validate())
}
}
Test looks similar to the one from book I mentioned earlier. But I'm getting
groovy.lang.MissingMethodException: No signature of method: racetrack.Race.validate() is applicable for argument types: () values: []
I'm stuck and didn't find any solution :/ Any help will be appreciated.
You're missing the mockForConstraintsTests() call. The common pattern is to do this in setUp()
protected void setUp() {
super.setUp()
mockForConstraintsTests(Race)
}
For details: http://mrhaki.blogspot.com/2009/04/unit-testing-constraints-in-domain.html
You should not use unit tests or mocking to test domain classes. Grails does create a unit test for domain classes and this should be changed. Move the class to the same package and folder under test/integration and change the base class to GroovyTestCase and you'll have a proper test that runs with the in-memory database and tests persistence, not the mocking framework.