I have a basic mapping defined in my UrlMappings.groovy If I run my app and go to /api/address/zip-code/12345 I get the show action to respond to the browsers request.
group("/api/address"){
"/zip-code"( resources: 'zipCode', includes: ['show'] )
}
I am trying to create a test to validate that my mapping works because I am going to create a ton of mappings here and I want them to backed by a test. This is my test.
package com.vega.foo
import com.vega.foo.address.ZipCodeController
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
import spock.lang.Specification
import org.codehaus.groovy.grails.web.mapping.UrlMappings
#TestFor(UrlMappings)
#Mock(ZipCodeController)
class UrlMappingsSpec extends Specification {
void "test zip code mapping"() {
expect:
assertForwardUrlMapping("/api/address/zip-code/12345", controller: 'zipCode', action: "show")
}
}
When I try and run this test I get the following error.
Compilation error compiling [unit] tests: BUG! exception in phase
'instruction selection' in source unit
'C:\websites********\test\unit\com\vega\foo\UrlMappingsSpec.groovy'
unexpected NullpointerException
This is about as basic of a URL Mappings test as you can write. What am I missing here?
PR. This is how I was able to pass unit spec.
Changes are almost what I had in comments.
Adding $id to url mapping.
Remove import org.codehaus.groovy.grails.web.mapping.UrlMappings from test.
Specifying the controller and the action explicitly in UrlMapping.
Related
When writing unit tests in Grails 3.x, we have to mock domains. Here is the example code.
package com.example.service
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
import spock.lang.Ignore
import spock.lang.Specification
#TestFor(SomeService)
#Mock([DomainA, DomainB])
class SomeServiceSpec extends Specification{
...
}
The problem is when a new domain is added, lets say DomainC and the unit tests are dependent upon DomainC, then those unit tests fails. We then have to manually have to add DomainC.
Is there a way to dynamically mock the domains?
#TestFor(SomeService)
#Mock([dynamically mock all domain objects here])
class SomeServiceSpec extends Specification{
...
}
Maybe this is what you need (from grails doc).
Alternatively you can also use the DomainClassUnitTestMixin directly
with the TestMixin annotation and then call the mockDomain method to
mock domains during your test:
#TestFor(BookController)
#TestMixin(DomainClassUnitTestMixin)
class BookControllerSpec extends Specification {
void setupSpec() {
mockDomain(Book)
}
...
Also mockDomains method exists for the list of domains, which you can retrieve by standard way from context.
I've been looking at https://media.readthedocs.org/pdf/graphene-python/latest/graphene-python.pdf for guidance on how to test that my graphql (Graphene, really since I have a python flask app) schema loads correctly. None of the versions for Graphene that I've installed support what the example shows, so I feel like I'm at a loss here.
from graphene.test import Client
def test_hey():
client = Client(my_schema)
executed = client.execute('''{ hey }''', context_value={'user': 'Peter'})
assert executed == {
'data': {
'hey': 'hello Peter!'
}
}
The error that I get: NameError: global name 'Client' is not defined suggests that Client doesn't exist in the graphene realm. Has anyone run into this issue?
You need to ensure that you have graphene available within the scope of your test.
As at this time, graphene.test.Client exists.
I was wondering as to how to build up a world of Domain class objects to use in my unit tests. What´s the best approach?
Say this is my code, ServiceX:
List<Course> getAllCoursesByType(String type) {
List<Course> list = Course.findAllByType(type)
list
}
This is the test for ServiceX:
import grails.buildtestdata.mixin.Build
import grails.test.mixin.TestFor
import grails.test.mixin.Mock
import spock.lang.Specification
#TestFor(ServiceX)
class ServiceXSpec extends Specification {
void "get all open courses"() {
given:
String type = "open"
when:
def list = service.getAllCoursesByType(type)
then:
list.size() == 4
}
}
How can I "pre populate" the test-db (memory) sow that I actually have 4 such objects in the list?
Create integration test for this. See an example here.
This is a judgement call for when to test using a slow integration test. The key is to test your code, not the Grails/hibernate DB code.
Integration tests should not be needed for the bulk of the service testing. I do think you need an integration test for the object interactions in a running system with a real DB. I tend to do that in GUI tests using GEB. These tests usually cover basic end-to-end scenarios. That tests the server side and the GUI interaction with the server.
In the GUI/GEB tests, I don't test all permutations and edge conditions of the service. I do most of that edge testing in unit tests.
I have found that with Grails, if one simple DB action works in an integration test, then most other simple DB actions work. The Grails domain mocks for save(), delete(), etc simulate the 'real' DB actions fairly well. Note: they do operate on objects in memory, so it is not exactly the same.
I don't use Spock, but with JUnit I use this approach (still works with Grails 3):
#TestFor(ServiceX)
#Mock([Course])
class ServiceXTests {
}
#Test
void testXYZ() {
def course= new Course(course: 'ABC')
assert course.save()
. . .
}
This appears to be supported with Spock. I would assume this creation of domain records belongs in the Spock 'given' section. Also, see Grails Testing.
Another great resource is to search the Grails source on Github. I learned a lot from their examples.
It turns out you can add / override methods to the domain classes (for example), something like this:
import grails.buildtestdata.mixin.Build
import grails.test.mixin.TestFor
import grails.test.mixin.Mock
import spock.lang.Specification
import grails.test.mixin.Mock
#Mock([Course])
#TestFor(ServiceX)
class ServiceXSpec extends Specification {
void "get all open courses"() {
given:
String type = "open"
Course.metaclass.static.findAllByType = { String type -> [new Course()]}
when:
def list = service.getAllCoursesByType(type)
then:
list.size() == 1
}
}
How do forcibly skip a unit test in Django?
#skipif and #skipunless is all I found, but I just want to skip a test right now for debugging purposes while I get a few things straightened out.
Python's unittest module has a few decorators:
There is plain old #skip:
from unittest import skip
#skip("Don't want to test")
def test_something():
...
If you can't use #skip for some reason, #skipIf should work. Just trick it to always skip with the argument True:
#skipIf(True, "I don't want to run this test yet")
def test_something():
...
unittest docs
Docs on skipping tests
If you are looking to simply not run certain test files, the best way is probably to use fab or other tool and run particular tests.
Django 1.10 allows use of tags for unit tests. You can then use the --exclude-tag=tag_name flag to exclude certain tags:
from django.test import tag
class SampleTestCase(TestCase):
#tag('fast')
def test_fast(self):
...
#tag('slow')
def test_slow(self):
...
#tag('slow', 'core')
def test_slow_but_core(self):
...
In the above example, to exclude your tests with the "slow" tag you would run:
$ ./manage.py test --exclude-tag=slow
I'm writing unit tests for a celery task using django-nose. It's fairly typical; a blank test database (REUSE_DB=0) that is pre-populated via a fixture at test time.
The problem I have is that even though the TestCase is loading the fixture and I can access the objects from the test method, the same query fails when executed within an async celery task.
I've checked that the settings.DATABASES["default"]["name"] are the same both in the test method and the task under test. I've also validated the that the task that's under test behaves correctly when invoked as a regular method call.
And that's about where I'm out of ideas.
Here's a sample:
class MyTest(TestCase):
fixtures = ['test_data.json']
def setUp(self):
settings.CELERY_ALWAYS_EAGER = True # seems to be required; if not I get socket errors for Rabbit
settings.CELERY_EAGER_PROPAGATES_EXCEPTIONS = True # exposes errors in the code under test.
def test_city(self):
self.assertIsNotNone(City.objects.get(name='brisbane'))
myTask.delay(city_name='brisbane').get()
# The following works fine: myTask('brisbane')
from celery.task import task
#task()
def myTask(city_name):
c = City.objects.count() # gives 0
my_city = City.objects.get(name=city_name) # raises DoesNotExist exception
return
This sounds a lot like a bug in django-celery 2.5 which was fixed in 2.5.2: https://github.com/celery/django-celery/pull/116
The brief description of the bug is that the django-celery loader was closing the DB connection prior to executing the task even eager tasks. Since the tests run inside a transaction the new connection for the task execution can't see the data created in the setUp.