Upgrading Spock unit tests from Grails 1.3.9 to Grails 2.3.9. But edit() test is failing - unit-testing

I am updating unit tests in a Grails project. We were originally using version 1.3.9 and now we are updating to version 2.3.9. I am using Spock.
I keep getting this error:
results:
junit.framework.AssertionFailedError: Condition not satisfied:
controller.edit() == [filterCategoryInstance: filterCategoryInstance]
| | | |
| null false John
com.xxxxxx.xxxxx.FilterCategoryController#20574000
Here is the controller code:
#Secured(["hasAnyRole('CM_ADMIN')"])
def edit() {
def filterCategoryInstance = FilterCategory.get(params.id)
if (!filterCategoryInstance) {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'dpFilterCategory.label', default: 'FilterCategory'), params.id])}"
redirect(action: "list")
}
else {
return [filterCategoryInstance: filterCategoryInstance]
}
}
and here is the test code:
#Mock([FilterCategory, FilterCategoryTag])
#TestFor(FilterCategoryController)
#TestMixin(DomainClassUnitTestMixin)
class FilterCategoryControllerSpec extends ExtendedControllerSpec {
def 'edit action: existing FilterCategory'() {
setup:
mockI18N(FilterCategoryController)
params.id = filterCategoryInstance.id
expect:
controller.edit() == [filterCategoryInstance: filterCategoryInstance]
where:
tag = new FilterCategoryTag(name: 'tag1')
filterCategoryInstance = new FilterCategory(name: "John",
submissionText:"John", sortOrder:0, 'filterCategoryTags': [tag])
}
And here is the ExtendedControllerSpec code. I hope I have included enough code:
I have looked at the following web pages for guidance:
#Mixin(MetaClassMixin)
class ExtendedControllerSpec extends Specification {
def props
protected void setup() {
//super.setup()
props = new Properties()
File file = new File("grails-app/i18n/messages.properties")
if (file.exists()) {
def stream = new FileInputStream(file)
props.load stream
stream.close()
}
mockI18N(controller)
}
def mockI18N = { controller ->
controller.metaClass.message = { Map map ->
if (!map.code)
return ""
if (map.args) {
def formatter = new MessageFormat("")
if (props.getProperty(map.code)) {
formatter.applyPattern props.getProperty(map.code)
}
return formatter.format(map.args.toArray())
} else {
if (props && props.hasProperty(map.code)) {
return props.getProperty(map.code)
} else {
return map.code
}
}
}
}
/**
* add dynamic methods in test setup.
*/
protected void addDynamicMethods() {
registerMetaClass(String)
String.metaClass.mixin StringUtils
}
protected GrailsUser mockGrailsUser() {
return Mock(GrailsUser)
}
...
/**
* must call AFTER mockDpSercurityService
*/
protected void setHasRoleTrue() {
if (controller?.dpSecurityService?.metaClass) {
controller.dpSecurityService.metaClass.hasRole = {return true}
}
}
protected void setHasRoleFalse() {
if (controller?.dpSecurityService?.metaClass) {
controller.dpSecurityService.metaClass.hasRole = {return false}
}
}
protected void mockUserService() {
controller.dpUserService = new MockFor(UserService)
}
}
http://sanjaykanwar.blogspot.com/2012/07/grails-controller-test-with-spock.html
http://naleid.com/blog/2012/05/01/upgrading-to-grails-2-unit-testing

Looks like the if branch gets executed in edit() instead of the else branch because FilterCategory does not get saved and therfore does not get a proper id.

Related

how to write an test case for below groovy code?

def withLocal(Closure cl) {
def credentialsId = env.CREDENTIALS_ID
if (credentialsId) {
echo("credentials Id=${credentialsId}")
} else {
throw new Exception("credentials not setup - env.CREDENTIALS_ID")
}
}
Excepting shouldFail and ShouldPass test cases for above groovy code.
Depending on the test-framework, the code might be slightly different, but I would put it like so:
class A {
def withLocal(Closure cl) {
def credentialsId = env.CREDENTIALS_ID
if (credentialsId) {
echo("credentials Id=${credentialsId}")
} else {
throw new Exception("credentials not setup - env.CREDENTIALS_ID")
}
}
}
// Test
// test 1 should pass: check if echo is called
// mock env with some value
A.metaClass.env = [ CREDENTIALS_ID:'abz123' ]
String out
// mock echo()
A.metaClass.echo = { out = it }
A a = new A()
a.withLocal{}
assert out == 'credentials Id=abz123'
// test 2 should fail: check if exception thrown
// mock env with empty map
A.metaClass.env = [:]
a = new A()
try{
a.withLocal{}
}catch( e ){
assert e.message == 'credentials not setup - env.CREDENTIALS_ID'
}

Unit Test with Nsubstitute allways return null with Lambda expression on Repository pattern

inside of the method which I'm evaluating in my Unit Test I want to return a mocked value which call my repository pattern, but always return null.
I've tried with both options below but the behavior is the same (return null):
Repository.FindAsync<User>(Arg.Is<Expression<Func<User, bool>>>(x => x.Email == "Test")).Returns(new User() { FirstName = "Test"});
and
Repository.FindAsync<User>(x => x.Email == "Test").Returns(new User() { FirstName = "Test"});
I paste the whole code of my unit test
public class WhenTestingUser : WhenTesting<Customer>
{
private IRepository Repository { get; set; }
protected override void Given()
{
Repository = Fixture.Freeze<IRepository>();
Repository.Find<User>(Arg.Any<Expression<Func<User, bool>>>()).ReturnsNull();
Repository.FindAsync<User>(Arg.Is<Expression<Func<User, bool>>>(x => x.Email == "Test")).Returns(new User() { FirstName = "Test"});
}
protected override void When()
{
SystemUnderTest.UpdateUser().GetAwaiter();
}
[Test]
public void WhenCalled()
{
throw new NotImplementedException();
}
}
I'm working with AutoFixture.AutoNSubstitute, NSubstite and NUnit
The solution is:
[Test]
public void TestUnprocessedInvoicesByCatchingExpression()
{
Expression<Func<InvoiceDTO, bool>> queryUsed = null;
IList<InvoiceDTO> expectedResults = new List<InvoiceDTO>();
_invoiceRepository
.Find(i => true)
.ReturnsForAnyArgs(x =>
{
queryUsed = (Expression<Func<InvoiceDTO, bool>>)x[0];
return expectedResults;
});
Assert.That(_sut.GetUnprocessedInvoices(), Is.SameAs(expectedResults));
AssertQueryPassesFor(queryUsed, new InvoiceDTO { IsProcessed = false, IsConfirmed = true });
AssertQueryFailsFor(queryUsed, new InvoiceDTO { IsProcessed = true, IsConfirmed = true });
}
NSubstitute - Testing for a specific linq expression

Grails 2.4.5 controller unit test verify transaction has rolled back

Here is a simple controller
class UserController {
#Transactional
def update() {
try {
....
throw new Exception("test transaction rollback")
...
} catch( e ) {
transactionStatus.setRollbackOnly()
respond "{ "status":"error" }"
}
}
}
Here is a unit test spec
#TestFor(UserController)
class UserControllerSpec extends Specification {
when:''
controller.update()
then:'verify that transaction has been rolled back'
// it fails with missing property, whats the best way to check that it was rolled back ?
controller.transactionManager.transactionRolledBack == true
}
whats the best way to test that the transaction has been rolled back ?
After #BurtBeckwith suggestion tried an integration spec.
// Domain User.groovy
class User { String firstName; String lastName }
// UserController.groovy
class UserController {
static responseFormats = ['json', 'xml']
static allowedMethods = [update: 'PUT']
#Transactional
def update( UserCommand cmd ) {
User m = User.get(id)
m.firstName=cmd.firstName
m.lastName=cmd.lastName
m.save(failOnError:true,flush:true)
transactionStatus.setRollbackOnly()
}
}
class UserCommand { Long id; String firstName; String lastName }
// IntegrationSpec UserControllerIntegrationSpec.groovy
import grails.test.spock.IntegrationSpec
class UserControllerIntegrationSpec extends IntegrationSpec {
def controller
def sessionFactory
def setup() {
controller = new UserController()
}
void "test transaction rollback"() {
given:'a user'
User u = new User(firstName:'oldFirstName',lastName:'oldLastName')
u.save(flush:true,failOnError:true)
controller.request.method='PUT'
controller.request.contentType = "application/json"
controller.request.content = '{"id":u.id,"firstName":"newFirstName","lastName":"newLastName"}'.getBytes()
when:'an update that rollsback is called'
controller.update()
// clear so that we do not get data from cache.
sessionFactory.currentSession.flush()
sessionFactory.currentSession.clear()
then:'we should still see old data'
User u2 = User.get(u.id)
// The following fails, u.firstName has 'newFirstName' which is wrong on rollback
u2.firstName == 'oldFirstName'
u2.lastName == 'oldLastName'
}
}
// DataSource.groovy
test {
dataSource {
url = "jdbc:mysql://localhost/starter_app_test"
driverClassName = "com.mysql.jdbc.Driver"
pooled = true
properties {
...
defaultAutoCommit=false
}
}
}
Any ideas why in integration test data seems to get persisted even when we rollback ?

Unit test filter with a mocked service

I'm using Grails 2.3.8 and trying to create a unit test for a filter that uses a service.
The filter:
class LicenseFilters {
def licenseService
def filters = {
all(controller:'*', action:'*') {
before = {
if(!licenseService.checkLicense()){
redirect(controller:"licenseExpired")
return false
}
}
}
}
}
The spec, first attempt:
#TestFor(ExecutionTraceController)
#Mock(LicenseFilters)
class LicenseFiltersSpec extends Specification{
void "Test filter redirects when license is wrong"() {
given:
LicenseFilters bean=applicationContext.getBean("com.nortia.sgmentia.license.LicenseFilters")
bean.licenseService=this.buildLicenseServiceStub(false)
when:
withFilters(action:"list") {
controller.list()
}
then:
response.redirectedUrl == '/licenseExpired'
}
private LicenseService buildLicenseServiceStub(boolean ok){
LicenseService result=Stub(LicenseService)
result.checkLicense() >> ok
return result
}
}
But it turns out (by debugging) that the bean that I grab from the context it is NOT the same one that receives the request thus I still get a NPE.
In a second attempt I try using defineBeans:
void "Test filter redirects when license is wrong"() {
given:
defineBeans {
licenseService(MethodInvokingFactoryBean){
targetObject = this
targetMethod= "buildLicenseServiceStub"
arguments=[false]
}
}
when:
withFilters(action:"list") {
controller.list()
}
then:
response.redirectedUrl == '/licenseExpired'
}
But the mocked bean is neither bean instanciated nor inyected.
Should I try to inyect the service manually into the filter??
There was this issue https://jira.grails.org/browse/GRAILS-8976 but it is closed.
I came across a similar situation and was able to fix it by adding the service to the #Mock annotation, i.e. #Mock([LicenseFilters, LicenseService]).
In your case the spec would look something like the following:
#TestFor(ExecutionTraceController)
#Mock([LicenseFilters, LicenseService])
class LicenseFiltersSpec extends Specification {
void "Test filter redirects when license is wrong"() {
given:
defineBeans {
licenseService(MethodInvokingFactoryBean) {
targetObject = this
targetMethod = "buildLicenseServiceStub"
arguments = [false]
}
}
when:
withFilters(action: "list") {
controller.list()
}
then:
response.redirectedUrl == '/licenseExpired'
}
private LicenseService buildLicenseServiceStub(boolean ok) {
LicenseService result = Stub(LicenseService)
result.checkLicense() >> ok
return result
}
}
Note: that mocking the service in this manner will, by default, inject an instance of the actual LicenseService into your filter. So, if the above defineBeans block is removed the actual implementation of LicenseService.checkLicense() will be called.
I finally found a workaround to make it work going with the second approach (using defineBeans).
The service is not being autowired into the filter so I finally did it manually with a pseudo-singleton:
class LicenseFilters {
def licenseService
def filters = {
all(controller:'*', action:'*') {
before = {
if(!this.licenseService){
this.licenseService=applicationContext.getBean("licenseService")
}
if(!this.licenseService.checkLicense()){
redirect(controller:"licenseExpired")
return false
}
}
}
}
}
Quite ugly but a solution at least.
Hope it helps someone out there.

Cannot mock grails domain class

someone, please, explain why domain class behaves different when is mocked with new MockFor(..)?
I use grails 2.4.1.
I have create domain class GTest:
class GTest {
static constraints = {
}
String amethod() {
return "GTest.amethod"
}
}
And a groovy class DTest:
class DTest {
String amethod() {
return "DTest.amethod"
}
}
And here a groovy test:
class GroovyJUnitTest {
#Test
void testDTestAmethod() {
def mock = new MockFor(DTest)
mock.demand.amethod {
return "Mock DTest"
}
mock.use {
def dtest = new DTest()
// Here dtest.metaClass=groovy.mock.interceptor.MockProxyMetaClass#...
def ret = dtest.amethod()
// This assertation successes
assertEquals "Mock DTest", ret
}
}
#Test
void testGTestAmethod() {
def mock = new MockFor(GTest)
mock.demand.amethod {
return "Mock GTest"
}
mock.use {
def gtest = new GTest()
// Here dtest.metaClass=groovy.lang.ExpandoMetaClass#...
def ret = gtest.amethod()
// This assertation fails
assertEquals "Mock GTest", ret
}
}
}
So, this question is how should Domain class be mocked programmatically?
Thank you for explanation.
You should annotation your test with grails.test.mixin.TestFor.
#grails.test.mixin.TestFor(MyDomainClass)
class MyDomainClassTest {
// ...
}
See http://grails.org/doc/latest/guide/testing.html#unitTestingDomains for more details.