How do you test a spring bean within Grails? - unit-testing

This is a follow-on question to that posted here:
How to initialise/wire beans in Grails Spock unit tests?
I haven't managed to find an example of where a spring bean is written in java within src/java and which is then unit tested within Grails using Spock.
Given:
// MyBean.java
// this needs to be in java as it is playing with spring-data-neo4j
package com.me;
public class MyBean {
#Autowired
def someNeo4jBeanThatCannotBeTestedByItself
String readFromDb() {
// this will execute code to actually read from a DB
return "Hello from DB";
}
}
Note that "someNeo4jBeanThatCannotBeTestedByItself" is a bean that is associated with spring-data-neo4j and I want to see that my code actually writes stuff here, so I want my unit/integration test to load spring beans (I don't want to mock this out).
What does the test case look like, is it an Integration test? I've tried a couple of variations, but can't get the spring beans to be initialised by Grails test-app.

I know this is old post. As this is not answered yet, i'm trying to answer. If you figured out already, you can ignore.
I believe for this you can write Unit Test. But if this class is under, src/groovy or src/java spring autowire doesn't work. You need to add bean,someNeo4jBeanThatCannotBeTestedByItself and MyBean, in `resources.groovy' file as shown below:
beans={
someNeo4jBean (Neo4jBeanClass)
myBean(MyBean){
someNeo4jBeanThatCannotBeTestedByItself = ref(someNeo4jBean)
}
}
You can remove #Autowired annotation in your bean,MyBean
Now for spec to work , you need to add this property to your spec, static loadExternalBeans = true, then it loads beans present in resources.groovy file.
Sample Spec:
#TestMixin(GrailsUnitTestMixin)
class MyBeanSpec extends Specification {
static loadExternalBeans =true//this loads beans present in resources.groovy
def myBean
def setup() {
myBean= applicationContext.getBean("myBean")
//now you can use this `myBean` in test cases..
}
}
I also had similar situation and i got rid of with this approach.
Hope this helps.

Related

Thymeleaf: Do not render during unit test?

As I haven't gotten an answer for my other question here, I am looking for another approach. Is there a way to no not execute or include a fragment during unit testing?
I want to display the version and build number in the footer of my templates, thus I have the following line:
<div class="versionInfo">Version <span th:text="${#buildProperties.getVersion()}"></span></div>
This works well when running the application, but during unit test I get the exception:
No bean named 'buildProperties' available
In the other question I am looking for a way to get this bean during unit test, as an alternative I am now looking for a way to exclude this template during unit tests. Something like this:
<div class="versionInfo" th:if="${!isUnitTest}">Version <span th:text="${#buildProperties.getVersion()}"></span></div>
I am using the following annotations on my test class:
#RunWith(SpringRunner.class)
#WebMvcTest(SimpleController.class)
If it's a standard unit-test, use Mockito to mock the bean:
#RunWith(MockitoJUnitRunner.class)
public class SomeTest{
#Mock
private BuildProperties buildProperties;
...
Or, if it's a Spring MVC test:
#RunWith(SpringRunner.class)
#WebMvcTest(value = MyController.class)
public class MyControllerTest{
#MockBean
private BuildProperties buildProperties;
The version will be null, because all of the methods of the mocked bean returns null.
if you want to emulate a real version you can add something like this to your test or to the setUp() method
given(buildProperties.getVersion()).willReturn("whatever");
--------------- edit
Unfortunately all of the above solutions work only if the buildProperties bean was added to the model directly.
But in your case you use the bean directly as a SpEL bean reference. Unfortunately I don't know any way to check if a bean exists in the context via SpEL.
Also, it's not a good practice to add extra code into your code for checking if it's running in test mode.
So I think the best solution if you create a nested test configuration class and define a default BuildProperties bean there.
#TestConfiguration
public static class TestConfig {
#Bean
BuildProperties buildProperties() {
return new BuildProperties(new Properties());
}
}
Or you can use #Import(TestConfig.class) if you need this extra configuration in multiple test classes.
I got a hint from a colleague that works for this question.
Just add an application.properties to src/test/resources with a custom property:
isUnitTest=true
Then I can simply check for this in my thymeleaf template:
<div class="versionInfo" th:if="${#environment.getProperty('isUnitTest') != 'true'}">Version <span th:text="${#buildProperties.getVersion()}"></span></div>
Though if someone finds a way to achieve this automatically with a thymeleaf setting or property I didn't find so far, I will accept it as an answer.

Grails Unit Testing Issues

I am having issues while testing my grails controllers, as it depends on one service which seems not to be injected. I tried several ways (for ex. Extending classess like grailsunitestcase, specification) but I keep getting errors. The thing is that that service variable is null and I cant test my controller index method (which calls a render view) due to the exception...
I really need to know how to do this but I don't have a clue where to start...
Unit tests are just that. There is no grails 'environment' surrounding your controller. If the controller makes use of a service which is normally injected, you have to mock that service yourself.
#TestFor(SomeController)
#Mock([SomeService])
class SomeControllerSpec extends Specification
def "test some method"() {
given:
def mockService = mockFor(SomeService)
mockService.demand.someServiceMethod() { ->
return something
}
controller.someService = mockService.createMock()
when:
controller.someControllerMethod()
then:
// whatever checks are appropriate
}
}

Testing afterInsert in Grails

Simply, I have the following scenario:
class OwnedRights {
static belongsTo = [comp: Competition]
#Transactional
def afterInsert() {
// Erroring out here.
Event.findAllByComp(comp).each { event ->
// Do something with event.
}
}
}
When I attempt to save in my unit test with something like the following:
def ownedRights = new OwnedRights(params).save(flush: true, failOnError: true)
I am seeing the following stacktrace:
java.lang.NullPointerException
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
at org.codehaus.groovy.grails.orm.support.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:85)
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:209)
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:194)
This lead to me to this Jira Issue which indicated that I was not using the #Mock annotation, however in my test, I am mocking all used domain classes:
#Mock([OwnedRights, Sport, Competition, Event])
Is this a known problem with hibernate events containing GORM logic?
Attempts to Solve
I have attempted to override the afterInsert() and beforeDelete methods by using the metaClass:
OwnedRights.metaClass.afterInsert = null;
OwnedRights.metaClass.beforeDelete = null;
and
OwnedRights.metaClass.afterInsert = {};
OwnedRights.metaClass.beforeDelete = {};
Both of which had no effect on the outcome. If I comment out the afterInsert event, the save works perfectly.
You are mentioning #Mock. This can only be used in unit tests, but then you should never try to test transactions in unit tests.
That's a no-no. Test transactions in an integration test. The work they did in allowing you to have an in-memory GORM implementation is wonderful, but transactions are a database feature. You just can't expect an in-memory implementation (backed by a Map!!) to behave like a database. What you are testing is the behavior of the GORM implementation for unit tests, not your actual database. So the test is useless in the real world.
I used this annotation (in unit test file) to solve the problem.
#TestFor(FooBarService)
And yes, it's possible to test Service layer using unit tests (but some of GORM methods may not be available, depending of your Grails version)

What test to write?

I know this is a basic question but due to lack of my knowledge I couldn't start writing test for my application. So here I am trying to learn and understand what to test and how to test based on my application scenario.
Class MyController {
MyService service = new MyService();
List<String> myList = service.generateSomeList(keyVal);
model.add("myList", myList);
}
Class MyService {
ThirdPatryService extService = new ThirdPatryService ();
MyDao dao = new MyDao();
public List<String> generateSomeList(Long key) {
List<String> resultList = dao.fetchMyList(key);
extService.processData(resultList); //using 3rd party service to process result. It doesn't return anything.
return formattedList(resultList);
}
private List<String> formattedList(List<String> listToProcess) {
//do some formatting
}
}
Class MyDao {
List<String> fetchMyList(key) {
//Use DB connection to run sql and return result
}
}
I want to do both unit testing and integration testing. So some of my questions are:
Do I have to do unit testing for MyDao? I don't think so since I can test query result by testing service level.
What can be the possible test cases for service level? I can think of test result from db and test formatting function. Any other test that I missed?
While testing generateSomeList() method is that OK to create dummy String list and test it against result? Like code below Am I creating list myself and testing myself. IS this proper/correct way to write test?
#Test
public void generateSomeListTest() {
//Step 1: Create dummy string list e.g. dummyList =["test1", "test2", "test3"]
//Step 2: when(mydao.fetchMyList(anyLong()).thenReturn(dummyList);
//Step 4: result=service.generateSomelist(123L);
//Step 5: assertEquals(result[i], dummyList[i]);
}
I don't think I have to test third party service but I think I have to make sure it is being called. Is this correct? If yes how can I do that with Mockito?
How to make sure thirdparty service has really done the processing of my data. Since its return type is void how can I do test it really done its job e.g like send email
Do I have to write test for controller or I can just write integration test.
I really appreciate if you could answer these question to understand the testing part for the application.
Thanks.
They're not really unit tests, but yes, you should test your DAOs. One of the main points in using DAOs is precisely that they're relatively easy to test (you store some test data in the database, then call a DAO method which executes a query, and check that the method returns what it should return), and that they make the service layer easy to test by mocking the DAOs. You should definitely not use the real DAOs when testing the services. Ue mock DAOs. That willmake the service tests much simpler, and much much faster.
Testing the results from DB is the job of the DAO test. The service test should use a mock DAO that returns hard-coded results, and checks that the service foes what it should do with these hard-coded results (formatting, in this case)
Yes, it's fine.
Usually, it's sufficient to stub the dependencies. Verifying that they have been called is often redundant. In that case, it could be a good idea since the third party service doesn't return anything. But that's a code smell. Why doesn't it return something? See the method verify() in Mockito. It's the very first point in the Mockito documentation: http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#1
The third party service is supposed to have been tested separately and thus be reliable. So you're supposed to assume that it does what its documentation says it does. The test for A which uses B is not supposed to test B. Only A. The test of B tests B.
A unit test is usually simpler to write and faster to execute. It's also easier to test corner cases with unit tests. Integration tests should be more coarse-grained.
Just a note: what your code severely lacks as is is dependency injection. That's what will make your code testable. It's very hard to test as is because the controller creates its service, which creates its DAO. Instead, the controller should be injected with the service, and the service should be injected with the DAO. That's what allows injecting a mock DAO in the service to test the service in isolation, and to inject a mock service into the controller to test the controller in isolation.

using build-test-data plugin with Grails 2

I'm trying to use the build-test-data plugin (v. 2.0.4) to build test data in a unit test of a Grails 2.1.4 application.
The app has the following domain classes
class Brochure {
static constraints = {}
static hasMany = [pageTags: PageTag]
}
class PageTag {
static constraints = {
}
static belongsTo = [brochure: Brochure]
}
Then in my unit test I try to build an instance of PageTag with
#Build([Brochure, PageTag])
class BrochureTests {
void testSomething() {
PageTag pageTag = PageTag.build()
}
}
But it fails with the error
groovy.lang.MissingMethodException: No signature of method:
btd.bug.Brochure.addToPageTags() is applicable for argument types:
(btd.bug.PageTag) values: [btd.bug.PageTag : (unsaved)] Possible
solutions: getPageTags()
My example looks exactly the same as that shown in the plugin's docs, so I've no idea why this isn't working. A sample app that demonstrates the issue is available here.
Fixed in version 2.0.5
I commented on the linked github issue, but this is because of a perf "fix" in how grails #Mock annotation works.
This change pretty much removes all of the linking code that made it possible for BTD to work in unit tests.
The only way around it currently is to also add an explict #Mock annotation for all of the domain objects in the part of the domain graph that's required to build a valid object.
The test code will be quicker with this change, which is great, but it puts a larger burden on the developer to know and maintain these relationships in their tests (which is what BTD was trying to avoid :).