Unit testing for domain classes using Grails - unit-testing

Currently searching for tutorials, explanations and examples.
I've tried different examples and came up to different errors.
My current error is :
| Error Compilation error compiling [unit] tests: startup failed:
and in my test reports. It outputs this :
Unit Test Results - Summary
No tests executed.
My "UserSpec.groovy" code is this :
package newmyproject245
import grails.test.mixin.*
import spock.lang.Specification
#TestFor(User)
class UserSpec extends ConstraintSpecification {
def setup() {
Expectations.applyTo User
}
def cleanup() {
}
void testShouldDoNothing() {
Expectations.applyTo User
user."password is not blank"
user."password is not nullable"
user."name is not blank"
user."name is not nullable"
}
void testEventNameConstraints() {
Expectations.applyTo User
def user = new User()
user."name is not blank"
user."name is not nullable"
}
}
Can anybody help. I'm new in grails.
Thanks!
Additional to the above problem,
when I omitted the Contraints in class as shown :
class UserSpec extends Specification {
I came up to this error :
| Running 1 unit test... 1 of 1
| Failure: initializationError(org.junit.runner.manipulation.Filter)
| java.lang.Exception: No tests found matching grails test target
pattern filter from org.junit.runner.Request$1#12c27788
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:35)
at org.junit.runner.JUnitCore.run(JUnitCore.java:138)
| Completed 1 unit test, 1 failed in 0m 0s
| Error Fatal error running tests: Not-null property references a transient value - transient instance must be saved before current operation : newmyproject245.Order.product -> newmyproject245.Product; nested exception is org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : newmyproject245.Order.product -> newmyproject245.Product (Use --stacktrace to see the full trace)
someone help. Again, Thanks!

I already got the answer. See code for reference :
UserSpec.groovy
package project101
import grails.test.mixin.TestMixin
import grails.test.mixin.support.GrailsUnitTestMixin
import spock.lang.Specification
/**
* See the API for {#link grails.test.mixin.support.GrailsUnitTestMixin} for usage instructions
*/
#TestMixin(GrailsUnitTestMixin)
#TestFor(User)
class UserSpec extends Specification {
def user
def setup() {
user = new User(firstName: 'FIRSTNAME', lastName: 'LASTNAME', address: 'Finland', username: 'user1', password: 'pass123', userType: 'ADMIN')
}
def cleanup() {
user = null
}
void "Test if User handles"() {
given:
setup()
when: "User field has null value"
user?.username = null
then: "Validation returns false"
user?.validate() == false
user?.errors?.hasFieldErrors('username') == true
}
}
And make sure that the dbCreate of the test environment is "create-drop" to avoid such errors. Found in DataSource.groovy
test {
dataSource {
pooled = true
dbCreate = "create-drop"
Regards,
Thanks! (^_~)

Related

Spock unit test using spring data causing errors in Optional

I'm starting to perform tests using the Spock Framework in a Spring Boot + Spring Data project.
The problem occurs when I try to Mock my repository, but specifically in some method that the return is Optional.
Cannot invoke method orElse() on null object
java.lang.NullPointerException: Cannot invoke method orElse() on null object
at br.com.moskit.jivochat.service.UserService.getResponsible(UserService.groovy:37)
at br.com.moskit.jivochat.service.UserServiceTest.Retrive the responsible of interaction in JivoChat by configs of plugin item(UserServiceTest.groovy:65)
My implemetation of test:
class UserServiceTest extends Specification {
UserService userService
void setup() {
userService = new UserService()
userService.userRepository = Mock(UserRepository)
GroovyMock(Optional)
}
def "Retrive the responsible of interaction in JivoChat by configs of plugin item"() {
given: 'that exist a collection of JivoChat interaction configurations'
List<Map> agents = null
Map configs = [responsibleId: 1]
userService.userRepository.findById(_) >> Optional.of(new User(username: "XPTO")).orElse("null")
when: 'the main method is called'
User user = userService.getResponsible(configs, agents)
then: 'the method get last agent and search in DB by e-mail'
1 * userService.userRepository.findById(_)
}
}
My method:
User getResponsible(Map configs, List<Map> agents) {
//Ommited...
Integer responsibleId = configs.responsibleId as Integer
Optional<User> userOptional = userRepository.findById(responsibleId)
User user = userOptional.orElse(null)
user
}
This is a classic one and the answer can be found in Spock manual chapter "Combining Mocking and Stubbing":
NOTE: Mocking and stubbing of the same method call has to happen in the same interaction.
So the solution looks like this:
package de.scrum_master.stackoverflow.q66208875
class User {
int id
String username
}
package de.scrum_master.stackoverflow.q66208875
class UserRepository {
Optional<User> findById(int id) {
Optional.of(new User(id: id, username: "User #$id"))
}
}
package de.scrum_master.stackoverflow.q66208875
class UserService {
UserRepository userRepository = new UserRepository()
User getResponsible(Map configs, List<Map> agents) {
Integer responsibleId = configs.responsibleId as Integer
Optional<User> userOptional = userRepository.findById(responsibleId)
User user = userOptional.orElse(null)
user
}
}
package de.scrum_master.stackoverflow.q66208875
import spock.lang.Specification
class UserServiceTest extends Specification {
UserService userService
void setup() {
userService = new UserService()
userService.userRepository = Mock(UserRepository)
}
def "retrieve the responsible of interaction in JivoChat by configs of plugin item"() {
given: 'that exist a collection of JivoChat interaction configurations'
List<Map> agents = null
Map configs = [responsibleId: 1]
when: 'the main method is called'
User user = userService.getResponsible(configs, agents)
then: 'the method get last agent and search in DB by e-mail'
1 * userService.userRepository.findById(_) >> Optional.of(new User(username: "XPTO"))//.orElse("null")
}
}
See how I combined stubbing the method result and verifying the mock interaction in one line?
You also do not need any GroovyMock(Optional), whatever that was meant for. You also want to make sure to get the findById(_) result type right and remove the false .orElse("null").

Grails Spock unit test requires to mock transaction manager

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 {
}

Unit test fails

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.

Grails build-test-data Plugin - Can't Find TestDataConfig.groovy

I'm trying to utilize the build-test-data plugin in my Grails (v2.4.3) app to assist with test data creation for unit testing, but while running my unit tests the plugin cannot find TestDataConfig.groovy to load my specified values (for unique constraint tests, etc).
I've installed the plugin via including it in BuildConfig.groovy:
plugins {
...
test ":build-test-data:2.2.0"
...
}
I've ran the following command to create the TestDataConfig.groovy template, which places the file at \grails-app\conf\:
grails install-build-test-data-config-template
I've followed the general instructions on the plugin wiki to come up with a properly formatted file:
testDataConfig {
sampleData {
'<path>.User' {
def a = 1
username = { -> "username${a++}" }
}
}
}
(Where path is the fully-qualified class name.)
In my tests, I am using the following general format:
import grails.buildtestdata.TestDataConfigurationHolder
import grails.buildtestdata.mixin.Build
import grails.test.mixin.TestFor
import spock.lang.Specification
import spock.lang.Unroll
#TestFor(User)
#Build(User)
class UserSpec extends Specification {
def setup() {
mockForConstraintsTests(User)
TestDataConfigurationHolder.reset()
user = User.buildWithoutSave()
}
#Unroll
void "test #field must be unique"() {
given: 'a User exists'
user.save(flush: true)
when: 'another User is created with a non-unique field value'
def nonUniqueUser = User.buildWithoutSave()
nonUniqueUser."$field" = user."$field"
then: 'validation fails and the field has a unique constraint error'
!nonUniqueUser.validate()
nonUniqueUser.errors.errorCount == 1
nonUniqueUser.errors.getFieldError("$field").code == 'unique'
where:
field << ['username', '<some other field>']
}
}
But, when the test is run (using IntelliJ IDEA) TestDataConfig.groovy cannot be found via the following method in the plugin:
static Class getDefaultTestDataConfigClass() {
GroovyClassLoader classLoader = new GroovyClassLoader(TestDataConfigurationHolder.classLoader)
String testDataConfig = Holders.config?.grails?.buildtestdata?.testDataConfig ?: 'TestDataConfig'
try {
return classLoader.loadClass(testDataConfig)
} catch (ClassNotFoundException ignored) {
log.warn "${testDataConfig}.groovy not found, build-test-data plugin proceeding without config file"
return null
}
}
So the test continues on without a config file and I do not get uniquely generated data sets.
I've even tried explicitly including the file in Config.groovy:
grails.buildtestdata.testDataConfig = "TestDataConfig"
But, the same method in the plugin shows that Holders.config? is null.
I've looked at a few solutions to a similar problem here on StackOverflow with nothing working in my case; I cannot figure out how to get my app to detect the presence of the TestDataConfig.groovy file.
Any ideas? Thanks so much!

Grails integration test - redirect action returns null

This is a small integration Junit that I'm having difficulty with. I've re-written this several different ways and the current way is straight out of the Grails manual - but it still returns null. I don't see the error; I thought it might be a spelling error but I've checked all those. I've tried redirectUrl and redirectedUrl - still returns null.
Controller snippet:
#Transactional(readOnly = true)
def saveReportError() {
redirect(action:'reportError')
}
Test:
#Test
void "test save error report"() {
controller.saveReportError()
assertEquals '/reportSiteErrors/reportError', controller.response.redirectUrl
}
I recommend to implement the test as a unit test like this.
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(SimpleController)
class SimpleControllerSpec extends Specification {
void 'test index'() {
when:
controller.index()
then:
response.redirectedUrl == '/simple/hello'
}
}
Using a unit test has the advantage of speed.