How do I use executeQuery in grails testcase?
A error : groovy.lang.MissingMethodException: No signature of method ***.executeQuery() is applicable for argument types: () values: []
I have already called mockDomain.
By the way, it is in unit test.
Thanks!
There's no support for HQL queries in unit tests yet, but we're working on it. But you shouldn't be doing persistence tests with mocks. Persistence tests should be done against a database in an integration test.
I usually move HQL queries to the domain class as static query methods. This way they're easy to mock in a unit test of a controller, service, etc. and then I test the method as part of the domain class integration test.
For example I'd have
class User {
String username
String password
...
static List findAllUsersBlahBlah(String foo, boolean bar) {
executeQuery('from User u where ...')
}
}
Then in a unit test I can mock that method with fake data since I don't care about persistence in a controller unit test - I know that it's properly tested in the correct place and I want to focus on the class under test, not its collaborators:
def users = [new User(...), new User(...)]
User.metaClass.static.findAllUsersBlahBlah = { String foo, boolean bar -> users }
We have successfully mocked executeQuery with Grails 2.0 in our project
#TestFor(BookController)
#TestMixin([DomainClassUnitTestMixin,ServiceUnitTestMixin])
#ConfineMetaClassChanges([Book])
class BookControllerSpec extends Specification{
mockDomain(Book)
Book.metaClass.static.executeQuery = {a,b,c-> return [Book]}
In Grails 2.5.4 you can use GroovyMock for mocking static methods implemented in Java:
GroovyMock(Book, global: true)
I just tested - it works also for _.executeQuery()
Related
I'm running into an issue where a unit test that extends HibernateSpec is failing due to the sessionFactory not being injected into the service under test. Whenever a method on the sessionFactory is called during the test, I get a NullPointerException (e.g. java.lang.NullPointerException: Cannot invoke method getClassMetadata() on null object) and the test subsequently fails.
I'm using Grails 3.2.4 and Hibernate 5.
This was working when the test used #TestMixin(HibernateTestMixin), but it looks like with some updates, the mixin is deprecated and suggests using HibernateSpec instead.
Here's a snippet from my test:
class TestDatabaseServiceSpec extends HibernateSpec {
def setup() {
}
def cleanup() {
}
void "test method"() {
when:
service.method()
then:
true
}
}
And here is a snippet from the service under test:
void method() {
...
TABLE_NAMES.add(sessionFactory.getClassMetadata('MyDomain').tableName)
...
}
I have tried to set service.sessionFactory in setup method as well as setupSpec method with the sessionFactory available in the test, but that did not help unfortunately. I have thought about using an integration test, but I would really like to see if I can continue to have this unit test work as it was before. Does anyone know if I am I doing something incorrectly or if there is a workaround/solution for this?
Thank you!
Viewing source code of HibernateSpec could give some hint. Could be there is no getSessionFactory() method in Hibernate 5 grails plugin that you are using.
I am using org.grails.plugins:hibernate5:6.0.6 with grails 3.2.5 and sessionFactory is not null for me in unit tests.
I understand that it is not always possible to upgrade, but it could give an idea what is the source of the problem.
Update:
service.sessionFactory = sessionFactory
also must be called in test setup.
What worked for me was to add the annotation #FreshRuntime to the spec and to add a doWithSpring closure to the test that sets up the sessionFactory for me (i.e. sessionFactory(InstanceFactoryBean, sessionFactory, SessionFactory)). Also, I made sure to add both service.sessionFactory = sessionFactory and service.transactionManager = transactionManager to the setupSpec method. Finally, I needed to override getDomainClasses() to work with all of the domain objects I wanted to in the test. Thanks for all the help!
The Test Mixins have been deprecated for the new traits since 3.2.3.
https://docs.grails.org/latest/guide/testing.html
Since Grails 3.3, the Grails Testing Support Framework is used for all
unit tests. This support provides a set of traits.
However, I still find myself using HibernateSpec as I can get multiple Domain classes from that, and the ServiceUnitTest for the service as well. The HibernateSpec has the needed sessionFactory.
E.g.
class MyServiceSpec extends HibernateSpec implements ServiceUnitTest<MyService>{
List<Class> getDomainClasses() { [Tag, TagLink, TagLinkValue, TagValue, TestDomain] }
...
def setup() {
service.sessionFactory = sessionFactory
...
}
// tests here with all those domain classes available and the service
}
The DataTest allows for multiple domain classes, but not the service as well.
https://testing.grails.org/latest/guide/index.html#unitTestingDomainClasses
the service test allows for the service, but not multiple domain classes.
https://testing.grails.org/latest/guide/index.html#unitTestingServices
You could use both of them together, but neither one of them has the session factory (that I could see), I'm on Grails 4.0.1. I looked through Github code for the latest and still don't see it available. Plus, the DataTest doesn't a hibernate session, it uses a SimpleMap instead so you can't use hql with it, which I wanted.
My Service was using the statelessSession
def statelessSession = sessionFactory.openStatelessSession()
String queryString = "select DISTINCT(t.tagRef) from com.fmr.aps.taggable.TagLink t group by t.tagRef order by t.tagRef ASC"
Query query = statelessSession.createQuery(queryString)
query.setReadOnly(true);
ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY);
So I needed a unit test trait or base class with it and I spent several hours trying to make the new traits give me what I wanted. Even I began subclassing the DataTest class to try and make it give me the sessionFactory, but eventually just went with the HibernateSpec and it's nice to be able to run that one test class with several Domains, the Service and the sessionFactory.
With just simple following controller action spock integration-test. Here is my Test.
#Integration
#Rollback
class TestControllerSpec extends Specification {
def setup() {
}
def cleanup() {
}
void "test something"() {
setup:
def c = new TestController()
c.index()
expect:
c.response.contentType !=null
}
}
getting following Exception
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at grails.web.api.WebAttributes$Trait$Helper.currentRequestAttributes(WebAttributes.groovy:45)
at grails.web.api.ServletAttributes$Trait$Helper.getRequest(ServletAttributes.groovy:42)
I've been doing this and it seems to work fine:
Add field:
#Autowired
WebApplicationContext ctx
In setup():
GrailsWebMockUtil.bindMockWebRequest(ctx)
In cleanup():
RequestContextHolder.resetRequestAttributes()
Unfortunately it might be a limitation in Grails 3, that you cannot use integration tests to test controllers.
To integration test controllers it is recommended you use
create-functional-test command to create a Geb functional test.
Source from Grails documentation
This seems to be a major change of direction from previous versions of grails. If you really need to test a controller in an integration test, you could try doing this:
NOTE: I realize this might be a bad practice, and it goes against Grails documentation, but sometimes you also need to test things more programmatically, where unit tests aren't sufficient, and are Geb tests aren't granular enough.
#TestFor(TestController) // This will provide a mocked "controller" reference
#Integration
#Rollback
class TestControllerSpec extends Specification {
// If TestController uses any services, have them autowired into this test
#Autowired
SomeService someService
def setupSpec() {
// Now connect those services to the controller
controller.someService = someService
}
void "test something"() {
when:
controller.index()
then:
response.contentType != null
}
}
WARNING: After some additional work with this format I did find a problem. Using #TestFor will call Holders.clear() when it is complete, which means that there will not be a grailsApplication object in Holders. This will cause problems if you have any integration tests that run after one that uses the approach above. After much digging, it doesn't look like there is an easy (or even hard) way of making this work, which is possibly why it is not supported in Grails 3. That being said, one option is to mark other integration tests with #TestFor, so that the Holders class will be properly populated. Is this a hack? Yes it is! You will need to decide if it is worth the effort of adding this overhead to all tests. In my case it was only one other integration test that needed this (as it is a small application), but if it was more than that I would not use this approach.
I am using the spring security core plugin within my grails application and by default it creates me a User class. I can mock this using the #Mock([User]) annotation on my test class.
In my application I have several types of User so I created subtypes which works great in the application itself.
Subtype1 extends User
Subtype2 extends User
This is handled in grails perfectly fine and the database reflects this too. In my code however, I do have methods which can be called by general Users so I use the User.get(id) since the id is the same for both Subtype and Parent.
If I mock User and Subtype and then create a Subtype object as follows
#TestFor(MyController)
#Mock([Subtype1,User])
class MyControllerSpec extends Specification {
def test_methodName() {
setup:
Subtype1 sub = new Subtype1(username:"blah",password:"blah",.....).save()
when:
controller.methodName(sub.id)
then:
//Some tests here
}
Then the following code is annotated to show the outcomes
class MyController() {
methodName(long id) {
User user = User.get(id) //This returns null
Subtype1 sub = Subtype1.get(id) //This works
}
}
In the application when not being tested both work however when I mock them it fails and doesn't let me get parents when created as a child.
Any idea what I'm doing wrong?
It looks like this just isn't possible within a Unit test, whether intentional or not.
Writing the test as an integration test works fine.
With grails 2.4, when you create a controller for example, it creates a unit test class such as:
#TestFor(SessionService)
class SessionServiceSpec extends Specification {
def setup() {
}
def cleanup() {
}
void "test something"() {
}
}
so you create 20 controllers, and get 20 test classes.
When you try to run grails test-app, it fails with the following error:
java.lang.Exception:
No tests found matching grails test target pattern filter from org.junit.runner.Request
It never gets to run our integration tests.
So tests Grails creates for you do not work out of the box.
We could delete all the created test specs classes, but then we kind of want them there ready for if we want to write them.
is there a way to run our integration tests, without running the unit tests (which are broken) or:
is there a way to fix the test so they don't fall over? Someone posted add a valid when/then, but we don't know what to put in this, as what we have tried still generates the same exceptions.
It's a shame Grails doesn't tell you which tests or class throws this exception.
This looks like a weird argument to me. When you create a controller, unit spec is created for it by default based on a template which can be easily tailored according to your need.
grails install-templates
does it for you. Now to answer your questions:
Yes there is a way to only run integration tests.
grails test-app integration:
After using install-templates modify the Controller.groovy template under src\templates\testing to something
like:
#artifact.package#import grails.test.mixin.TestFor
import spock.lang.Specification
/**
* See the API for {#link grails.test.mixin.web.ControllerUnitTestMixin}
* for usage instructions
*/
#TestFor(#artifact.testclass#)
class #artifact.name# extends Specification {
def setup() {
}
def cleanup() {
}
void "test something"() {
expect:
1 == 1
}
}
This will not fail your test when run but it defeats the whole purpose of
writing failing test -> modify code -> fixing test approach
of TDD. I would rather implement a failing test and then write minimal logic in controller to pass the test.
I have two Grails Projects in Eclipse. I am referencing one project inside the other with the Configure Build Path setup. Running tests however throws an error java.lang.IllegalStateException: Method on class [com.example.domain.Phone] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly.
Normally this is fixed with a #Mock (using Mockito) or mockDomain(), but I am not in a unit test so these items are not seen.
How can I test my service layer through an integration test if it cannot see my domain objects that I need to use? These domain objects are separated because of the need to use them across multiple projects.
If your GORM classes are not in the same package as your Application class then you need to add the ComponentScan annotation to the Application class to indicate where you GORM classes are. Example:
#ComponentScan(basePackages=['foo.bar', 'my.company'])
class Application {
....
If you are writing tests do not forget:
Annotations in Spec. #IntegrationTest is important
#ContextConfiguration(loader = SpringApplicationContextLoader, classes = ConfigTest)
#EnableAutoConfiguration
#IntegrationTest
class PaymentServiceSpec extends Specification{
// Tests with GORM entities
}
Class where hibernate is injected
#SpringBootApplication
#Import(HibernateGormAutoConfiguration)
class CoreConfigTest {
}
Because of #IntegrationTest it is necessary to have an Application class for tests
#SpringBootApplication
class TestApplication {
static void main(String[] args) {
run TestApplication, args
}
}
I am using this dependencies:
runtime 'org.postgresql:postgresql:9.3-1102-jdbc41'
compile("org.grails:gorm-hibernate4-spring-boot:1.1.0.RELEASE") {
exclude module: 'spring-boot-cli'
exclude module: 'groovy-all'
}
compile("org.springframework.boot:spring-boot-starter-jdbc:1.2.2.RELEASE")
There is GORM for Spring Boot available. Examples in https://spring.io/guides/gs/accessing-data-gorm/
If you are writing tests, you can use the HibernateTestMixin or use HibernateDatastoreSpringInitializer to initialize GORM.