grails / grails-testing-support

Trait-based testing library for Grails framework
http://testing.grails.org
Apache License 2.0
11 stars 21 forks source link

Problem Testing Data Services #18

Open jeffscottbrown opened 6 years ago

jeffscottbrown commented 6 years ago

(moving issue from https://github.com/grails/grails-data-mapping/issues/1020 to here)

See https://github.com/jeffbrown/servicetestproblem

Domain:

package servicetestproblem

class Person {
    String name
}

Data Service:

package servicetestproblem

import grails.gorm.services.Service

@Service(Person)
abstract class PersonService {
    abstract List<Person> list()
}

Unit test:

package servicetestproblem

import grails.testing.gorm.DataTest
import grails.testing.services.ServiceUnitTest
import spock.lang.Specification

class PersonServiceSpec extends Specification implements ServiceUnitTest<PersonService>, DataTest {

    def setupSpec() {
        mockDomain Person
    }

    void 'first test'() {
        expect:
        service.list().size() == 0
    }

    void 'second test'() {
        expect:
        service.list().size() == 0
    }
}

There is no reason to have a unit test like that of course but this is a simple example that demonstrates the problem. The second test method will fail with the following:

Condition failed with Exception:

service.list().size() == 0
|
java.lang.reflect.InvocationTargetException

    at servicetestproblem.PersonServiceSpec.second test(PersonServiceSpec.groovy:20)
Caused by: java.lang.reflect.InvocationTargetException
    at grails.testing.services.ServiceUnitTest$Trait$Helper.mockArtefact(ServiceUnitTest.groovy:66)
    at org.grails.testing.ParameterizedGrailsUnitTest$Trait$Helper.getArtefactInstance(ParameterizedGrailsUnitTest.groovy:48)
    at grails.testing.services.ServiceUnitTest$Trait$Helper.getService(ServiceUnitTest.groovy:83)
    ... 1 more
Caused by: java.lang.IllegalStateException: Could not register object [servicetestproblem.$PersonServiceImplementation@42339ea2] under bean name 'personService': there is already object [servicetestproblem.$PersonServiceImplementation@42339ea2] bound
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.registerSingleton(DefaultSingletonBeanRegistry.java:130)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerSingleton(DefaultListableBeanFactory.java:936)
    at grails.testing.gorm.DataTest$Trait$Helper.mockDataService(DataTest.groovy:101)
    ... 4 more
jameskleeh commented 6 years ago

@jeffbrown Is this issue resolved with https://github.com/grails/grails-testing-support/commit/7b4443f02ba25f96e997e44e89b634d9dc0298ec ?

niravassar commented 6 years ago

During creation of the dataservices guide, i tried different ways of testing. i came across this issue that jeff had filed.

It is true that his project works for the first test and fails for the second, in Grails 3.3.1.

However, in grails 3.3.6, the same tests do not work at all. The service is not even accessed in this test. Basically, unit testing with the service is not working. I am not sure that we want it to work because testing with DataTest is not with a Hibernate implementation. In the guide, i recommended testing with HibernateSpec, and also with an integration test.

I created a sample app with this same code that shows it failing.

https://github.com/niravassar/dataservice-unit-test

This is the error

Condition failed with Exception:

service.list().size() == 0
|
java.lang.reflect.InvocationTargetException

    at PersonDataServiceSpec.first test(PersonDataServiceSpec.groovy:15)
Caused by: java.lang.reflect.InvocationTargetException
    at grails.testing.services.ServiceUnitTest$Trait$Helper.mockArtefact(ServiceUnitTest.groovy:66)
    at org.grails.testing.ParameterizedGrailsUnitTest$Trait$Helper.getArtefactInstance(ParameterizedGrailsUnitTest.groovy:48)
    at grails.testing.services.ServiceUnitTest$Trait$Helper.getService(ServiceUnitTest.groovy:83)
    ... 1 more
Caused by: java.lang.NoSuchMethodError: org.grails.datastore.mapping.core.AbstractDatastore.getService(Ljava/lang/Class;)Lorg/grails/datastore/mapping/services/Service;
    at grails.testing.gorm.DataTest$Trait$Helper.mockDataService(DataTest.groovy:96)
    ... 4 more

PersonDataServiceSpec > first test FAILED
    org.spockframework.runtime.ConditionFailedWithExceptionError at PersonDataServiceSpec.groovy:15
        Caused by: java.lang.reflect.InvocationTargetException at PersonDataServiceSpec.groovy:15
            Caused by: java.lang.NoSuchMethodError at PersonDataServiceSpec.groovy:15
niravassar commented 6 years ago

@jeffbrown I am thinking we can close this out, based on the notion that we should use HibernateSpec and/or integration suite to test DataServices. If you agree, let me know. thanks.