I have the following as my unit test:
void testCreateDealer() {
mockForConstraintsTests(Dealer)
def _dealer= new Dealer( dealerName:"ABC",
Email:"abc-motors#global.com",
HeadOffice:"",
isBranch:false)
assertFalse _dealer.validate()
}
But when I run the test I get the following error:
No signature of method: static com.myCompany.Dealer.findByDealerNameIlike() is applicable for argument types: (java.lang.String) values: [ABC]
I use some custom constraints in my domain class. How Can I test this?
static constraints = {
dealerName(blank:false, validator:
{ val, obj ->
def similarDealer = Dealer.findByDealerNameIlike(val)
return !similarDealer || (obj.id == similarDealer.id)
}
)
Try changing mockForConstraintsTests() to mockDomain() - you're using a Dealer.findX() method in the constraint, which relies on the Dealer domain.
Incidentally, the test will still fail unless you've created a similar dealer in the setUp() method of the test class.
In unit tests, even with mockDomain, the id attribute of domain objects is not set automatically, or auto-incremented. All of the domain objects you create will have an id of null unless you explicitly set it.
Your test is probably failing because the test obj.id == similarDealer.id is true, since they both have id: null. Try setting the id attribute of your mocked dealer objects.
Related
Lets say i have a domain A which has a custom validator for property P
static constraints = {
P validator: { val, obj ->
(A.executeQuery("SELECT COUNT(*) FROM A cei WHERE cei.event.id = ?", [val.id])[0] <= 1)
}
In the unit test how can i mock the P property of domain A so that i don't get the error i am getting when running unit test. The error i get when running unit test is shown below. The setup code instantiates domain A as shown below.
void setUp(){
inv = new A(P: rg).save(flush: true)
Error is
java.lang.UnsupportedOperationException: String-based queries like [executeQuery] are currently not supported in this implementation of GORM. Use criteria instead.
Note: These are fake code.
The best option for me, is encapsulate the inner code of the validator inside a service. And then, mock that service in your unit test.
But the error thrown is that executeQuery is not available, but criteria is.
So change your code for using a criteria instead.
P validator: { val, obj ->
A.withCriteria{
eq('event', Event.findById(val.id))
projections{
count('id')
}
}[0] < = 1
}
I am new in unit-testing in Grails application using Spock. However I would like to ask the following question. Lets say I want to run a test for the following function testfun.
class TestFun{
boolean testfun(long userId, long orderId){
User user = User.findByUserId(userId)
if(user == null)return false
Order order = Order.findByUserAndId(user, orderId)
HashMap<String, Object> = orderContent
orderContent= order.orderContent // the order has an element orderContent for storing the elements that one user orders
if(orderContent!=null){
orderContent.put("meal",1)
order.orderContent = orderContent
return true
}
return false
}
}
The corresponding unit test in that case would be:
class TestFun extends Specification {
def setup() {
GroovySpy(User, global: true)
GroovySpy(Order, global: true)
}
def "test funtest"() {
User user = new User(2).save()
Order order = new Order(3).save()
when:
service.testfun(2,3) == result
then:
2*User.findByUserId(2) >> Mock(User)
1*Order.findByUserAndId(_ as User, 1)>> Mock(Order)
result == true
}
}
However, I think that I have to mock the order.orderContent and I do not know how to mock it. Right now the test fails, because the orderContent is null so the testfun returns false.
Can anyone help me on that?
There are several things going on here, and hopefully fixing them will help you get the test running and passing.
I can't recall for certain, but I believe GroovySpy is an old feature, that isn't used with Spock tests. Instead of using that to mock a domain class, you should be using the #Mock annotation before the class definition, to specify which domain classes you would like to mock.
While you can mock the domain classes, you'll also need to actually populate the in-memory database with those objects, either in a setup: block, or in a setup() method, if they are needed for multiple tests.
You mention creating mocks, and using the Spock Mock() method will create a mock of that object, but you don't want to use that for domain objects. It is more typically used for service classes that will be manually injected into your test class.
When saving a mock domain class, I would suggest including the parameters flush: true, failOnError: true, that way any validation that fails will be indicated immediately and on the appropriate line. Without this, you can get some strange errors to occur later in the tests.
I don't know what you're doing in the when: block, but you should not be doing an assertion with == at that point, do all of those in the then: block.
Given all of this, I think you test class should look more like this:
#Mock([User, Order])
class TestFun extends Specification {
def setup() {
// This object will have an id of 1, if you want a different id, you can either specify it, or create more objects
User user = new User(first: "john", last: "doe").save(flush: true, failOnError: true)
new Order(user: user).save(flush: true, failOnError: true)
}
def "test funtest"() {
User user = new User(2).save()
Order order = new Order(3).save()
when:
boolean result = service.testfun(1, 1)
then:
// Optionally you can just use "result" on the next line, as true will be assumed
result == true
}
}
I have the following piece of code inside a service class named OrderService in Groovy on Grails. I want to make a unit test for this class. User and Order are domain classed. A user has many orders.
boolean testfun(long userId, lond orderId){
User user = User.findByUserId(userId)
if(user == null)return false
Order order = Order.findByUserAndId(user, orderId)
if(order == null)return false
return true
}
The unit test that I am trying to write is the following (using Spock):
#TestFor(OrderService)
#Mock([User, Order])
class OrderServiceSpec extends Specification{
def "test funtest"() {
User user = new User(2)
Order order = new Order()
order.metaClass.id = 3// I want to assign the id of the order in domain
order.save()
user.addToOrders(order)
user.save()
expect:
service.testfun(2,3) == true
}
}
However this test fails because the order is null. Can anyone help me?
Another question is: is this test a unit test? or should I write an integration test in grails?
It depends on what you're actually trying to test, but this can be a unit test—I'd just recommend modifying it a little bit to isolate only the service method that you're interested in testing. You're not looking to test the domain classes at all, so it's best to mock/stub the behavior that you need from them to test the service functionality.
A good way to do this is with Spock's support for interaction based testing via mock objects. Basically we specify that when the service's testfun() method is called, we expect User.findById() to be called once and Order.findByUserAndId() to be called once as well. Spock then allows us to stub out each method call so that we specify what we want the method to return. When we run the test, the stub will be used, not the actual GORM method.
Some complexity lies with stubbing out static methods (like GORM methods), but you can use a GroovySpy to get the job done.
Also, I'm assuming you meant to use User.findById() instead of User.findByUserId()?
Something along these lines should work for you:
def "test funtest"() {
setup:
// Global so that it replaces all instances/references of the
// mocked type for the duration of the feature method.
GroovySpy(User, global: true)
GroovySpy(Order, global: true)
when:
def result = service.testfun(2,3)
then:
// No need to return real objects, so use a mock
1 * User.findById(2) >> Mock(User)
1 * Order.findByUserAndId(_ as User, 3) >> Mock(Order)
result == true
when:
result = service.testfun(2,3)
then:
1 * User.findById(2) >> null
result == false
}
Note that we've isolated the service method. Any collaborating objects (User and Order) are only being interacted with via stubs and we can test the functionality of the service method without worrying about GORM at all.
I am trying to test some methods within a Domain object, the code seems to execute (based on log) but the assertions fail.
The code being tested (extendDates), is working, I am just adding the unit tests now.
I assume I am doing something wrong in the mocking.The following is a simplified version of my code. Based on the log output, the assertion should pass.
class EventDate{
Date startDate
Date endDate
belongsTo = [Appointments owner]
static constraints = {
endDate(nullable:true, blank:false)
startDate(nullable:false, blank:false)
}
}
class Appointments {
hasMany = [ eventDates: EventDate]
belongsTo = [ customer: Customer ]
def extendDates(start,end){
//some logic on eventDates...
EventDate(startDate:start,endDate:end, owner:this).save(flush:true,failOnError:true);
}
}
#TestFor(Appointments)
#Mock([EventDate])
class AppointmentsTests {
void testDateExtend(){
assertTrue domain != null
assertTrue domain instanceof Appointments
//Log indicates the correct execution and creation of event
domain.extendDates(new Date(),null)
//following returns NullPointerException
assertTrue domain.eventDates.size() == 1
}
}
In your example you test for
if (create_new)
The variable "create_new" is never set and would therefore test false using groovy truth logic, thus never executing the if statement.
The if statement never adds anything to the "eventDates" property of Appointments, this would also mean that the assertion would fail.
I'm thinking your example is incomplete and therefore cannot help you until you expand it.
Yes, you will get NullPointerException in the assert condition. The reason being that, you are creating instance of EventDate in the extendDates method but you are not really adding it to the eventDates list in Appointments domain.
So, you have to modify your that method something like:
// Initialize with empty array to avoid NPE
List<EventDate> eventDates = []
static hasMany = [ eventDates: EventDate]
def extendDates(start, end) {
EventDate instance = EventDate(start, end).save()
// And add it to the list of events
this.addToEventDates(instance)
this.save(flush: true)
}
Now, your test case should work your assert condition.
(Also, looks like you have not added nullable constraint in end but passing the null value while creating instance of EventDate, may be not included in sample code)
I'm sure this is a fairly common situation. I'm using the Spring Security Core plugin and want to create a domain model that has a Person limited to certain roles:
class Workgroup {
Person manager
...
static constraints = {
manager(validator: {mgr ->
// it feels like there should be a more elegant, groovy way of doing this.
def auths = mgr.getAuthorities();
def returny = false
auths.each {
if(it.authority == 'ROLE_MANAGER')
{
returny = true
}
}
return returny
})
}
}
This test fails like a mofo:
void testInvalidManager() {
def nick = new Person(username:'Nick')
def nonManagerRole = new Role(authority:'ROLE_EMPLOYEE')
UserRole.create(nick,nonManagerRole)
def awesome = new Workgroup(name:'mooCows', manager:nick)
mockForConstraintsTests(Workgroup, [awesome])
assertFalse awesome.validate()
assertEquals "validator", awesome.errors["manager"]
}
testInvalidManager Error No signature of method: users.UserRole.save() is applicable for argument types: (java.util.LinkedHashMap) values: [[flush:false, insert:true]] Possible solutions: wait(), any(), wait(long), use([Ljava.lang.Object;), isCase(java.lang.Object), each(groovy.lang.Closure)
groovy.lang.MissingMethodException: No signature of method: users.UserRole.save() is applicable for argument types: (java.util.LinkedHashMap) values: [[flush:false, insert:true]]
Possible solutions: wait(), any(), wait(long), use([Ljava.lang.Object;), isCase(java.lang.Object), each(groovy.lang.Closure)
at users.UserRole.create(UserRole.groovy:32)
at users.UserRole.create(UserRole.groovy)
at users.UserRole$create.call(Unknown Source)
at users.WorkgroupTests.testInvalidManager(WorkgroupTests.groovy:17)
Is this better covered in Integration than Unit Testing? Do I need to mock UserRole (if so, how?)? How are these types of tests normally done?
UserRole.create() calls save(), so you need to use mockDomain() instead of just mockForConstraintsTests().
But that's only if you're ok with testing the domain model with mocks, which I would never do. The mocking support in Grails should be used when testing Controllers or other classes that use domain classes but shouldn't be bothered with real persistence, creating a database (even in-memory), etc. By removing that dependency you're concentrating on the current tier, trusting that the other tier is already properly tested. But when you use mocking to test domain classes, you're really just testing the mocking framework. So I always use integration tests for domain classes so they run against a real database.
To answer the implicit question from your code example, I'd write the constraint as
static constraints = {
manager validator: { mgr ->
mgr.authorities.find { it.authority == 'ROLE_MANAGER' } != null
}
}
The issue with its bulk is that you're using each() when a regular for loop would be preferable since you can return from a for loop. Use each() only when you really want to invoke the closure on every instance. Here's one that's less groovy than the other one but uses a for loop:
static constraints = {
manager validator: { mgr ->
for (auth in mgr.getAuthorities()) {
if (it.authority == 'ROLE_MANAGER') {
return true
}
}
return false
}
}