is there a less bloated way to test constraints in grails? - unit-testing

Is there a less bloated way to test constraints? It seems to me that this is too much code to test constraints.
class BlogPostTests extends GrailsUnitTestCase {
protected void setUp() {
super.setUp()
mockDomain BlogPost
}
void testConstraints() {
BlogPost blogPost = new BlogPost(title: "", text: "")
assertFalse blogPost.validate()
assertEquals 2, blogPost.errors.getErrorCount()
assertEquals "blank", blogPost.errors.getFieldError("title").getCode()
assertEquals "blank", blogPost.errors.getFieldError("text").getCode()
blogPost = new BlogPost(title: "title", text: ObjectMother.bigText(2001))
assertFalse blogPost.validate()
assertEquals 1, blogPost.errors.getErrorCount()
assertEquals "maxSize.exceeded", blogPost.errors.getFieldError("text").getCode()
}
}

I'd advise against testing getErrorCount(), as you'll make your tests fragile (as you add other constraints, you'll have to remember to update every instance of new BlogPost() anywhere in your test cases). Just check hasErrors().
Other than that... for each constraint, you need to generate some test data that violates it, call the validation routine, and assert on the errors. This is the code you need.
Refactor out some methods to remove the duplication. example:
private void assertConstraintWorks(clazz, fieldName, testData, expectedErrorCode) {
def instance = clazz.newInstance((fieldName): testData)
assertFalse instance.validate()
assertTrue instance.hasErrors()
assertEquals expectedErrorCode, instance.errors?.getFieldError(fieldName)?.code
}
void testConstraints() {
assertConstraintWorks BlogPost, 'title', '', 'blank'
assertConstraintWorks BlogPost, 'text', '', 'blank'
assertConstraintWorks BlogPost, 'text', ObjectMother.bigText(2001), 'maxSize.exceeded'
}

Ross Niemi, a coworker of mine, created the Domain Expectations plugin which uses a nice DSL for exercising and validating constraints on grails domain objects. We use it at my work place, and I've been very happy with it.

Maybe not the answer you want to hear, but: Do you really want to test the constraints defined in your domain model? In essence, what you are doing here is testing the validation framework of Grails rather than your own code. Don't get me wrong, tests are necessary (especially with dynamic languages like Groovy), but IMHO one shouldn't just blindly test everything that comes across. Maybe I'm just not too much of an hardcore TDD guy, but I just don't see the point here.

This blog post has a good description of unit testing constraints. One thing I didn't see above is the use of mockForConstraintsTests() (which eliminates need for mockDomain())
And to comment on Daniel, yes I would test the constraints defined in my domain model to assert that I have correctly constrained the domain model. You make a typo in a constraint declaration and you won't find it until an integration or functional test (and in the meantime will drive you nuts)

Related

Grails : Spock : Unit testing GORM domain class hooks

Usually I was ending up writing test cases for a Domain by writing them for constraints and any custom methods(created by us in application) as we know we shouldn't test obvious.
But the time we started using coverage plugin, we found that our domains line of code is not fully covered which was due to gorm hooks(onInsert, beforeUpdate) that we never wrote test cases for.
Is there a way we can test these. One possible way that seems obvious but not suitable is to call another method(containing all code which was earlier in hooks) within these hooks and test that method only and be carefree for hooks.
Any solutions...
Edit
Sample code in domain that I want to unit-test:
class TestDomain{
String activationDate
def beforeInsert() {
this.activationDate = (this.activationDate) ?: new Date()//first login date would come here though
encodePassword()
}
}
How can I unit-test beforeInsert or I would end up writing integration test case?
Perhaps a unit test like:
import grails.test.mixin.TestFor
#TestFor(TestDomain)
class TestDomainSpec extends Specification {
def "test beforeSave"() {
given:
mockForConstraintsTests(TestDomain)
when:
def testDomain = new TestDomain().save(flush:true)
then:
testDomain.activationDate != null
}
}

How do I mock local variables of a mocked class in a Spock test?

Let's say I have the following method in a service:
private void deleteItems(List<Item> itemsToDelete) {
def sql = new Sql(dataSource)
itemsToDelete?.each { Item item ->
sql.execute("DELETE FROM owner_item WHERE item_id = ${item.id}")
item.delete(flush: true, failOnError: true)
flushDatabaseSession();
}
}
How do I create a test for this method in the ItemServiceSpec? When I try it, I get either a DataSource "Must specify a non-null Connection" error or a nullPointerException on sql.
This is my existing test.
#TestFor(ItemService)
#Mock([Item])
#Build([Item])
class SubjectServiceSpec extends Specification {
...
def "delete items"() {
given:
Item item1 = Item.build().save(flush: true)
Item item2 = Item.build().save(flush: true)
Item.count() == 2
DataSource mockDataSource = Mock()
service.dataSource = mockDataSource
1 * deleteItems
when:
service.deleteItems([item1, item2])
then:
Item.count() == 0
}
}
What you are trying to do here, is to mock a dependency (DataSource) of a dependency (Sql). This normally leads to a situation, where you a not 100% aware of how the Sql interacts with the DataSource Object. If Sql changes private interaction with the Datasource in a Version Update, you have to deal with the situation.
Instead of mocking a dependency of a dependency you should the Sql Class directly. For this, the sql has to be some kind of explicit dependency that you can receive via DI or a method parameter. In this case you can just mock the execute call like so (choosen the way of a Expando-Mock, but you could also use Map or the Mock Stuff from Spock):
given:
def sqlMock = new Expando()
sqlMock.execute = { return 'what ever you want or nothing, because you mock a delete operation' }
service.sql = sqlMock
when:
service.deleteItems([item1, item2])
then:
assertItemsAreDeletedAndTheOwnerAsWell()
Thinking about the whole testcase, there a two major problems in my opinion.
The first one is, when you ask yourself what kind of certainty do you really get here by mocking out the whole sql stuff. In this case, the only thing that you are doing here is to interact with the db. When you mock this thing out, then there is nothing anymore that you could test. There is not many conditional stuff or anything that should be backed up by a unit test. Due to this, I would suggest to write only integration spec for this test-case where you have something like a H2DB for testing purposes inplace.
The second thing is, that you actually don't need the Sql Manipulation at all. You can configure GORM and Hibernate in a way do a automatic and transparent deletion of the owner of the item, if the item is deleted. For this, look at the docs (especially the cascade part) from GORM or directly in the Hibernate docs.
To sum it up: use cascade: 'delete' together with a proper integration test and you have a high amount of certainty and less boilerplate code.

unit testing the unique constraint on domain class

I'm using Grails 2.4.1 and having trouble understanding how to properly test a unique constraint on a domain class.
My domain class looks like:
class Person {
String name
static constraints = {
name( unique: true, blank: false )
}
}
and my test:
#TestFor(Person)
#TestMixin(GrailsUnitTestMixin)
class PersonSpec extends Specification {
void "name should be unique"() {
given:
mockForConstraintsTests Person
when:
def one = new Person( name: 'john' )
then:
one.save()
when:
def two = new Person( name: 'john' )
then:
! two.validate()
two.errors.hasFieldErrors( 'name' )
}
The second instance is validating despite apparently violating the unique constraint. Can someone please explain what's going on here and how I should best correct it?
Thanks!
--john
I do not think it is the best approach to test the constraints by triggering them. Generally we want to test that our code is working and not that Grails is validating the constraints.
Why test the framework (i.e. Grails)? Hopefully the Grails people have done that already :-)
(yes, there are situations were it makes sense to check the framework, but I don't think this is one).
So the only thing to test is that we have placed the correct constraints on the domain class:
#TestFor(Person)
class PersonSpec extends Specification {
void "name should have unique/blank constraints"() {
expect:
Person.constraints.name.getAppliedConstraint('unique').parameter
! Person.constraints.name.getAppliedConstraint('blank').blank
}
}
If it is worth writing that test is another question...
This is exactly kind of mistake I used to do as a beginner. Testing grails stuff whether it is working as expected or not. Testing framework related stuff not a good idea. It means then testing all constraints, predefined methods and even save(), update() etc. So it would mean testing grails framework again rather than developing your application.
Testing should generally consists of testing your business logic related stuff.

How to mock a CakePHP behavior for unit testing

I've just started with unit testing in CakePHP (yay!) and ran into the following challenge. Hope somebody can help me :-)
Situation
My model uses a Behavior to send changes to an API after saving it locally. I would like to fake all calls made to the API during the test (those will be tested seperately) to save load on the API server, and more important, not actually save the changes :-)
I'm using CakePHP 2.4.1.
What I've tried
Read the docs. The manual shows how to do this for Components and Helpers but not for Behaviors.
Google. What I've found:
A Google Group post which says it simply "isn't possible". I don't take no for an answer.
An article explaining how to mock an object. Comes pretty close.
The code from the article reads:
$provider = $this->getMock('OurProvider', array('getInfo'));
$provider->expects($this->any())
->method('getInfo')
->will($this->returnValue('200'));
It might be the wrong direction, but I think that might be a good start.
What I want
Effectively: A snippet of code to demo how to mock a behavior in a CakePHP Model for unit testing purposes.
Maybe this question will result in an addition of the CakePHP manual too as an added bonus, since I feel it's missing in there.
Thanks in advance for the effort!
Update (2013-11-07)
I've found this related question, which should answer this question (partly). No need to mock up the API, instead I can create a Behavior test that the model will use.
I'm trying to figure out what that BehaviorTest should look like.
Use the class registry
As with many classes, behaviors are added to the class registry using the class name as the key, and for subsequent requests for the same object loaded from the classregistry. Therefore, the way to mock a behavior is simply to put it in the class registry before using it.
Full Example:
<?php
App::uses('AppModel', 'Model');
class Example extends AppModel {
}
class TestBehavior extends ModelBehavior {
public function foo() {
throw new \Exception('Real method called');
}
}
class BehaviorExampleTest extends CakeTestCase {
/**
* testNormalBehavior
*
* #expectedException Exception
* #expectedExceptionMessage Real method called
* #return void
*/
public function testNormalBehavior() {
$model = ClassRegistry::init('Example');
$model->Behaviors->attach('Test');
$this->assertInstanceOf('TestBehavior', $model->Behaviors->Test);
$this->assertSame('TestBehavior', get_class($model->Behaviors->Test));
$this->assertSame(['foo' => ['Test', 'foo']], $model->Behaviors->methods());
$model->foo();
}
public function testMockedBehavior() {
$mockedBehavior = $this->getMock('TestBehavior', ['foo', 'bar']);
ClassRegistry::addObject('TestBehavior', $mockedBehavior);
$model = ClassRegistry::init('Example');
$model->Behaviors->attach('Test');
$this->assertInstanceOf('TestBehavior', $model->Behaviors->Test);
$this->assertNotSame('TestBehavior', get_class($model->Behaviors->Test));
$expected = [
'foo' => ['Test', 'foo'],
'bar' => ['Test', 'bar'],
'expects' => ['Test', 'expects'], // noise, due to being a mock
'staticExpects' => ['Test', 'staticExpects'], // noise, due to being a mock
];
$this->assertSame($expected, $model->Behaviors->methods());
$model->foo(); // no exception thrown
$mockedBehavior
->expects($this->once())
->method('bar')
->will($this->returnValue('something special'));
$return = $model->bar();
$this->assertSame('something special', $return);
}
}

Groovy: Verify construction of stubbed URL

The test class below verifies that a simple HttpService gets content from a given URL. Both the implementations shown make the test pass, though one is clearly wrong because it constructs the URL with an incorrect argument.
To avoid this and correctly specify the behaviour I want, I'd like to verify that in the use block of the test case, I construct one (and only one) instance of the URL class, and that the url argument to the constructor is correct. A Groovy enhancement seems like it would let me add the statement
mockURLContext.demand.URL { assertEquals "http://www.foo.com", url }
but what can I do without that Groovy enhancement?
Update: Replaced "mock" with "stub" in the title, as I'm only interested in checking the state not necessarily the detail of the interactions. Groovy has a StubFor mechanism that I haven't used, so I'll leave my code as is, but I think you could just replace MockFor with StubFor throughout.
import grails.test.*
import groovy.mock.interceptor.MockFor
class HttpServiceTests extends GrailsUnitTestCase {
void testGetsContentForURL() {
def content = [text : "<html><body>Hello, world</body></html>"]
def mockURLContext = new MockFor(URL.class)
mockURLContext.demand.getContent { content }
mockURLContext.use {
def httpService = new HttpService()
assertEquals content.text, httpService.getContentFor("http://www.foo.com")
}
}
}
// This is the intended implementation.
class HttpService {
def getContentFor(url) {
new URL(url).content.text
}
}
// This intentionally wrong implementation also passes the test!
class HttpService {
def getContentFor(url) {
new URL("http://www.wrongurl.com").content.text
}
}
What does mocking the URL get you? It makes the test difficult to write. You won't be able to react to feedback the mock objects give you about the design of the API of the URL class, because it's not under your control. And if you don't precisely fake the behaviour of the URL and what it exposes about the HTTP protocol, the test will not be reliable.
You want to test that your "HttpService" object actually loads the data correctly from a given URL, copes with different content type encodings correctly, handles different classes of HTTP status code appropriately, and so forth. When I need to test this kind object -- one that merely wraps some underlying technical infrastructure -- I write a real integration test that verifies that the object really does use the underlying technology correctly.
For HTTP I write a test that creates an HTTP server, plugs a servlet into the server that will return some canned data, passed the URL of the servlet to the object to make it load the data, check that the loaded result is the same as the canned data used to initialise the servlet, and stop the server in the fixture tear-down. I use Jetty or the simple HTTP server that is bundled with JDK 6.
I'd only use mock objects to test the behaviour of objects that talk to the interface(s) of that object I've integration tested.
Putting on my "Programming in the Small" and "Unit test 100%" hat, you could consider this as a single method that does too many things. You could refactor the HttpService to:
class HttpService {
def newURLFrom(urlString) {
new URL(urlString)
}
def getContentText(url) {
url.content.text
}
def getContentFor(urlString) {
getContentText(newURLFrom(urlString))
}
}
This would give you a few more options for testing, as well as split out the factory aspect from the property manipulation. The testing options are bit more mundane then:
class HttpServiceTests extends GroovyTestCase {
def urlString = "http://stackoverflow.com"
def fauxHtml = "<html><body>Hello, world</body></html>";
def fauxURL = [content : [text : fauxHtml]]
void testMakesURLs() {
assertEquals(urlString,
new HTTPService().newURLFrom(urlString).toExternalForm())
}
void testCanDeriveContentText() {
assertEquals(fauxHtml, new HTTPService().getContentText(fauxURL));
}
// Going a bit overboard to test the line combining the two methods
void testGetsContentForURL() {
def service = new HTTPService()
def emc = new ExpandoMetaClass( service.class, false )
emc.newURLFrom = { input -> assertEquals(urlString, input); return fauxURL }
emc.initialize()
service.metaClass = emc
assertEquals(fauxHtml, service.getContentFor(urlString))
}
}
I think that this makes all the assertions that you want, but at the cost of sacrificing test readability in the last case.
I would agree with Nat about this making more sense as an integration test. (You are integrating with Java's URL library on some level.) But assuming that this example simplifies some complex logic, you could use the metaclass to override the instances class effictvely partially mocking the instance.
It's tough to mock out JDK classes that are declared final... Your problem, as you reference through the enhancement, is that there is no way to create a URL other than calling the constructor.
I try to separate the creation of these kinds of objects from the rest of my code; I'd create a factory to separate the creation the URLs. This should be simple enough to not warrant a test. Others take a typical wrapper/decorator approach. Or you may be able to apply the adapter pattern to translate to domain objects that you write.
Here is a similar answer to a surprisingly similar problem: Mocking a URL in Java
I think this demonstrates something that a lot of people learn after doing more testing: the code we write to make things more testable is meant to isolate what we desire to test from what we can safely say is already tested somewhere else. It's a fundamental assumption we have to make in order to do unit testing. It can also provide a decent example of why good unit tests aren't necessarily about 100% code coverage. They have to be economical, too.
Hope this helps.
What exactly are you expecting to have fail? It is not readily apparent what you are trying to test with that code. By Mocking URL.getContent you are telling Groovy to always return the variable content when URL.getContent() is invoked. Are you wishing to make the return value of URL.getContent() conditional based upon the URL string? If that is the case, the following accomplishes that:
import grails.test.*
import groovy.mock.interceptor.MockFor
class HttpServiceTests extends GrailsUnitTestCase {
def connectionUrl
void testGetsContentForURL() {
// put the desired "correct" URL as the key in the next line
def content = ["http://www.foo.com" : "<html><body>Hello, world</body></html>"]
def mockURLContext = new MockFor(URL.class)
mockURLContext.demand.getContent { [text : content[this.connectionUrl]] }
mockURLContext.use {
def httpService = new HttpService()
this.connectionUrl = "http://www.wrongurl.com"
assertEquals content.text, httpService.getContentFor(this.connectionUrl)
}
}
}