I've been using javax.sql.DataSource for processing sql queries in my services:
class SomeService {
javax.sql.DataSource datasource
def someFoo(foo) {
def sql = new Sql(dataSource)
def query = "SELECT DISTINCT * FROM someDomain WHERE FOO = ${foo}"
def result = sql.rows(query)
return result
}
}
And I have created some unit tests for the services
class SomeServiceTests extends GrailsUnitTestCase {
def service
protected void setUp() {
super.setUp()
service = new SomeService()
}
def testSomeFoo() {
service.datasource = new javax.sql.DataSource
def result = service.someFoo("foo")
assertNotNull result
}
}
I believe my services run good.
But, I get the following error from the test :
Caused an ERROR
Must specify a non-null Connection
java.lang.NullPointerException: Must specify a non-null Connection
so, is that a problem with the testing framework or am I missing something here ?
I've also tried a similar situation with an executeQuery but that too throws a "MissingMethodException".
Can I create unit tests with these, because the same problem occurred with integration tests as well?
Is there any way that I could mock any of these or isolate the data parts, so as to just verify the methods?
Related
In Grails 3.1.12, I want to unit test a service:
#Transactional
class PlanService {
List<Plan> getPlans(Map params) {
def currentUser = (User)springSecurityService.getCurrentUser()
return Plan.findAllByCompany(currentUser.employer, params)
}
}
Like this:
#TestFor(PlanService)
#Mock([Plan, User, Company])
class PlanServiceSpec extends Specification {
void "Retrieve plan from the current user"() {
setup:
// create and save entities here
when: "the plans are retrieved"
def params = null
def plans = service.getPlans(params)
then: "the result should only include plans associated to the current user's company"
plans.size() == 2
}
Running the test from the console:
grails> test-app my.PlanServiceSpec -unit
Fails with:
my.FundingPlanServiceSpec > Retrieve plan from the current user FAILED
java.lang.IllegalStateException at PlanServiceSpec.groovy:48
and in the test report (HTML):
java.lang.IllegalStateException: No transactionManager was specified.
Using #Transactional or #Rollback requires a valid configured transaction manager.
If you are running in a unit test ensure the test has been properly configured
and that you run the test suite not an individual test method.
Now if I comment out the #Transactional annotation in the service, the test passes, but that's not the intended implementation. I am able to work around the problem by mocking the transaction manager:
service.transactionManager = Mock(PlatformTransactionManager) {
getTransaction(_) >> Mock(TransactionStatus)
}
But this seems very awkward, if not wrong.
Is there some incantation I forgot to invoke?
EDIT: looks similar to an old bug, but it's been closed more than a year.
Have you tried what a comments says that fixes the problem? If not, try to annotate the test class with:
#TestMixin(DomainClassUnitTestMixin)
and then:
service.transactionManager = getTransactionManager()
Was getting the same error in grails 3.3.2 when trying to test transactional service.
adding DataTest interface solved the issue for me.
class HelloServiceSpec extends Specification implements ServiceUnitTest<HelloService>, DataTest {
}
I am new in Grails, I want to write unit tests for services using Spock. However I have the following issue.
import grails.transaction.Transactional
#Transactional
class BService {
boolean createB(){
return true
}
...
}
For this class I wrote the following test:
class BServiceTest extends Specification {
def "test createB"(){
given:
def service = new BService()
when:
def boolean temp
temp = service.createB()
then:
temp == true
}
}
The error I am getting when I run this test is the following:
java.lang.IllegalStateException: No transactionManager was specified. Using #Transactional or #Rollback requires a valid configured transaction manager. If you are running in a unit test ensure the test has been properly configured and that you run the test suite not an individual test method.
and it shows in GrailsTransactionTemplate.groovy:60
I would really appreciatie if anyone can give me a hint.
Add a #TestFor(BService) annotation to your unit test and use the instance of the service that it automatically provides. See http://grails.github.io/grails-doc/3.0.x/guide/testing.html for more information on testing.
Thank you ataylor for your reply. However I did a mistake, so I am now ansewring my own question.
First of all, the name conversion is wrong. When I create a service in grails there is automatically set a unit-test for this, so in that case I would have:
#TestFor(BService)
class BServiceSpec extends Specification {
def setup() {
User u = new User(1)
u.save()
}
def cleanup() {
}
def "test something"(){
}
}
In this case when I write a unit test, it runs.
The test that I had before was a functional test where I could not pass objects from the domain, so I had an error of the transactional manager.
I have a controller class with this code:
List<MultipartFile> files = []
List<String> convertedContents = []
def convertedFiles = [:]
try {
params.myFile.each {
if (((MultipartFile) it.value).empty) {
throw new NoUploadedFileException('Break .each closure due to empty input.')
}
files.add((MultipartFile) it.value)
}
} catch (NoUploadedFileException e) {
redirect uri: request.getHeader('referer')
return
}
convertedContents = converterService.convertToBase64(files)
(code omitted)
I also have a test:
def "sampleTest"() {
when:
controller.sendFax()
then:
thrown(NoUploadedFileException)
response.redirectedUrl == 'index.gsp'
}
What I'm trying to test is that my Controller would throw a "NoUploadedFileException" when no file are uploaded and the submit button is clicked.
This is the error:
Running 1 unit test... 1 of 1
| Failure: sampleTest(com.synacy.HomeControllerSpec)
| Expected exception com.synacy.NoUploadedFileException, but got
java.lang.NullPointerException
at org.spockframework.lang.SpecInternals.thrownImpl(SpecInternals.java:79)
at com.synacy.HomeControllerSpec.throws NoUploadedFileException and returns to the
same page when no file is uploaded(HomeControllerSpec.groovy:36)
Caused by: java.lang.NullPointerException: Cannot invoke method convertToBase64() on
null object
at com.synacy.HomeController.sendFax(HomeController.groovy:43)
at com.synacy.HomeControllerSpec.sampleTest(HomeControllerSpec.groovy:33)
It seems that it isn't going through the try-catch block, or if it is, the implementation is not working.
For a Unit test, in either setup: or when: you have to create the environment your controller is acting in.
Populate the request with whatever headers/params/data are appropriate -- headers, parameters, payload, whatever. Setup the grails application configuration with whatever is appropriate if needed.
Your NPE says that you aren't hitting the controller code you are trying to test. The NPE is because your controller doesn't have a converterService assigned/injected (it's a Unit test). You haven't set any params for your controller, so you aren't entering your .each block of code.
Perhaps controller.params.myFile = new MultipartFile() // just guessing here
Abbreviated example from one of my tests (I want to test the json response, so I have to format the request appropriately):
#TestFor(DirectoryController)
#Mock([SpringSecurityService,ConfigurationService,ConfigurationDomain,EntryDomain])
class DirectoryControllerSpec extends Specification
def "test getDirectorySources"() {
setup:
// not testing authentication, so just return true
SpringSecurityUtils.metaClass.static.ifAllGranted = { String role ->
return true
}
// mock the data to be returned from the configurationService call
def configuration = new ConfigurationDomain(id:2,name:'Mock Config',entries:[])
def typeEntry = new EntryDomain(key:'ldap01.type',value:'ad')
configuration.entries << typeEntry
def nameEntry = new EntryDomain(key:'ldap01.name',value:'LDAP01')
configuration.entries << nameEntry
// mock the configurationService
def mockConfigurationService = mockFor(ConfigurationService, true) // loose mock
mockConfigurationService.demand.getConfigurationById() { Long id ->
return configuration
}
controller.configurationService = mockConfigurationService.createMock()
when:
// setup the request attributes
request.setContentType('application/json')
request.method = 'GET'
request.addHeader('Accept','application/json')
controller.params.id = "2"
controller.getDirectorySources()
then:
response.getText() == '{"sources":[{"key":"ldap01","name":"LDAP01","type":"ad"}]}'
cleanup:
// reset the metaClass
SpringSecurityUtils.metaClass = null
}
}
Mock any services used by the controller; you aren't testing your converterService, so that should be mocked, and return a known value so you know what the controller should do in response to the data returned from the service.
In short, in a Unit test, you should control everything not in the immediate controller code.
You should mock your service so your test should look like:
#TestFor(MultipleFileUploadController)
#Mock([ConverterService])
class MultipleFileUploadControllerSpec extends Specification {
...
}
But your test will not pass because you handle NoUploadedFileException in controller, so it will not be caught anywhere in tests, so you should have fail with
Expected exception com.stackoverflow.NoUploadedFileException, but no exception was thrown
Remove the line thrown(NoUploadedFileException) from test.
Try mocking your service above your test class as:
#TestFor(MultipleFileUploadController)
#Mock([ConverterService])
This will solve your issue as spock will mock the ConverterService class for you and you can call its methods. Please keep in mind that each and every domains and services you use in your methods should be mocked in your test. Hope it will help.
I am trying to unit test a service that has a method requiring a request object.
import org.springframework.web.context.request.RequestContextHolder as RCH
class AddressService {
def update (account, params) {
try {
def request = RCH.requestAttributes.request
// retrieve some info from the request object such as the IP ...
// Implement update logic
} catch (all) {
/* do something with the exception */
}
}
}
How do you mock the request object ?
And by the way, I am using Spock to unit test my classes.
Thank you
This code seems to work for a basic unit test (modified from Robert Fletcher's post here):
void createRequestContextHolder() {
MockHttpServletRequest request = new MockHttpServletRequest()
request.characterEncoding = 'UTF-8'
GrailsWebRequest webRequest = new GrailsWebRequest(request, new MockHttpServletResponse(), ServletContextHolder.servletContext)
request.setAttribute(GrailsApplicationAttributes.WEB_REQUEST, webRequest)
RequestContextHolder.setRequestAttributes(webRequest)
}
It can be added as a function to your standard Grails unit test since the function name does not start with "test"... or you can work the code in some other way.
One simple way to mock these, is to modify the meta class for RequestContextHolder to return a mock when getRequestAttributes() is called.
I wrote up a simple spec for doing this, and was quite surprised when it didn't work! So this turned out to be a quite interesting problem. After some investigation, I found that in this particular case, there are a couple of pitfalls to be aware of.
When you retrieve the request object, RCH.requestAttributes.request, you are doing so via an interface RequestAttributes that does not implement the getRequest() method. This is perfectly fine in groovy if the returned object actually has this property, but won't work when mocking the RequestAttributes interface in spock. So you'll need to mock an interface or a class that actually has this method.
My first attempt at solving 1., was to change the mock type to ServletRequestAttributes, which does have a getRequest() method. However, this method is final. When stubbing a mock with values for a final method, the stubbed values are simply ignored. In this case, null was returned.
Both these problems was easily overcome by creating a custom interface for this test, called MockRequestAttributes, and use this interface for the Mock in the spec.
This resulted in the following code:
import org.springframework.web.context.request.RequestContextHolder
// modified for testing
class AddressService {
def localAddress
def contentType
def update() {
def request = RequestContextHolder.requestAttributes.request
localAddress = request.localAddr
contentType = request.contentType
}
}
import org.springframework.web.context.request.RequestAttributes
import javax.servlet.http.HttpServletRequest
interface MockRequestAttributes extends RequestAttributes {
HttpServletRequest getRequest()
}
import org.springframework.web.context.request.RequestContextHolder
import spock.lang.Specification
import javax.servlet.http.HttpServletRequest
class MockRequestSpec extends Specification {
def "let's mock a request"() {
setup:
def requestAttributesMock = Mock(MockRequestAttributes)
def requestMock = Mock(HttpServletRequest)
RequestContextHolder.metaClass.'static'.getRequestAttributes = {->
requestAttributesMock
}
when:
def service = new AddressService()
def result = service.update()
then:
1 * requestAttributesMock.getRequest() >> requestMock
1 * requestMock.localAddr >> '127.0.0.1'
1 * requestMock.contentType >> 'text/plain'
service.localAddress == '127.0.0.1'
service.contentType == 'text/plain'
cleanup:
RequestContextHolder.metaClass = null
}
}
I have a grails 2.1 app which has a controller that calls a method on a service, passing in a request and a response:
class FooController {
def myService
def anAction() {
response.setContentType('text/xml')
myservice.service(request,response)
}
I want to unit test this method. And I want to do so using GMock (version 0.8.0), so this is what I tried:
def testAnAction() {
controller.myService = mock() {
service(request,response).returns(true)
}
play {
assertTrue controller.anAction()
}
}
Now this fails saying that that it failed expectations for request.
Missing property expectation for 'request' on 'Mock for MyService'
However, if I write my test like this:
def testAnAction() {
def mockService = mock()
mockService.service(request,response).returns(true)
controller.myService = mockService
play {
assertTrue controller.anAction()
}
}
The test will pass fine. As far as I am aware they are both valid uses of the GMock syntax, so why does the first one fail and the second one not?
Cheers,
I assume you write your tests in a test class FooControllerTest generated by grails.
In a such way, FooControllerTest class is annoted by #TestFor(FooController) wich inject some usefull attributes.
So request is an attribute of your test class, not a variable in the local scope.
It's why it is not reachable from a internal Closure.
I'm convinced that following code could work (I have not tested yet) :
def testAnAction() {
def currentRequest = request
def currentResponse = response
controller.myService = mock() {
service(currentRequest,currentResponse).returns(true)
}
play {
assertTrue controller.anAction()
}
}