Thymeleaf: Do not render during unit test? - unit-testing

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.

Related

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

How do you test a spring bean within Grails?

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.

Http.Context with FakeApplication and illusive mock method

In my tests I create a fake application per test method:
#Before
public void startFakeApplication() {
this.fakeApplication = fakeApplication();
start(this.fakeApplication);
}
#After
public void killFakeApplication() {
stop(this.fakeApplication);
this.fakeApplication = null;
}
Some of the tests use functionality that checks if the request is secure or not:
public boolean isHttps() {
Http.Request req = Controller.request();
return req.getHeader("x-forwarded-proto") != null
&& req.getHeader("x-forwarded-proto").contains("https");
}
That fails saying:
There is no HTTP Context available from here
Which is pretty strange, since it's running on a fake app, why can't it know that and create a fake request?
Oh well, I found this: Play framework 2.2.1: Create Http.Context for tests which introduced me to the mocking approach, so I was eager to give it a go and try to mock the Http.Context in the same way, the problem is that I can't seem to find the mock method...
In that thread he's using import static org.mockito.Mockito.* (which is where I assume the mock method is located) but I don't have that package, org.mockito only has one sub package named internal and I can't find any mock method there.
In the official documentation of Play! the only place talking about it is the Scala Test section and they use: import org.specs2.mock._ but there too I wasn't able to locate this mock method.
I'm using Play 2.2.2 (java).
Any ideas? Thanks.
I solved the same problem adding to my build.sbt the library dependency of Mockito:
libraryDependencies += "org.mockito" % "mockito-core" % "1.10.19"
Then I run play compile and play eclipse and magically the mockito library became available after refreshing the whole project in Eclipse.
And yes, mock() is a method of org.mockito.Mockito.
I had the same problem of Play not locating the mock function, and eventually realised that I hadn't extended my test class with Mockito;
import org.specs2.mock._
class TestClass extends Specification with Mockito
Just thought I'd add this as it has taken me ages to resolve and the above solution didn't work for me ......may save someone some time :)

Grails Domain Class Unit Test, issue with Constraint setup - java.lang.NoClassDefFoundError: Could not initialize

My grails unit test for domain class is throwing this exception:
| java.lang.NoClassDefFoundError: Could not initialize class com.pkg.common.Configuration
at com.pkg.DomainClass$__clinit__closure1.doCall(DomainClass.groovy:10)
at org.grails.datastore.mapping.config.groovy.MappingConfigurationBuilder.evaluate(MappingConfigurationBuilder.groovy:72)
at org.grails.datastore.mapping.config.AbstractGormMappingFactory.createMappedForm(AbstractGormMappingFactory.java:51)
at org.grails.datastore.mapping.keyvalue.mapping.config.GormKeyValueMappingFactory.createMappedForm(GormKeyValueMappingFactory.java:37)
at org.grails.datastore.mapping.keyvalue.mapping.config.GormKeyValueMappingFactory.createMappedForm(GormKeyValueMappingFactory.java:27)
at org.grails.datastore.mapping.keyvalue.mapping.config.KeyValuePersistentEntity.<init>(KeyValuePersistentEntity.java:33)
at org.grails.datastore.mapping.keyvalue.mapping.config.KeyValueMappingContext.createPersistentEntity(KeyValueMappingContext.java:89)
at org.grails.datastore.mapping.model.AbstractMappingContext.addPersistentEntityInternal(AbstractMappingContext.java:159)
at org.grails.datastore.mapping.model.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:152)
at grails.test.mixin.domain.DomainClassUnitTestMixin.mockDomain(DomainClassUnitTestMixin.groovy:133)
at grails.test.mixin.domain.DomainClassUnitTestMixin.mockDomain(DomainClassUnitTestMixin.groovy:129)
Following is my stripped down Domain class :
package com.pkg
import com.pkg.common.Configuration
class DomainClass {
String subject
static constraints = {
subject(maxSize: 100, nullable: false, blank: false, matches: Configuration.ALLOWED_TEXT_CHARS)
}
}
My com.pkg.common.Configuration class is just a Singleton with static properties :
package com.pkg.common
import grails.util.Holders
class Configuration{
final public static String ALLOWED_TEXT_CHARS = "${Holders.grailsApplication.metadata["allowed.text.chars"]}"
}
"allowed.text.chars" is a RegEx defined in application.properties :
allowed.text.chars=[a-zA-Z0-9\\p{L}\\p{Digit}_"` $ \\-'_&;\:#()/\\.,!\\?%*|<>]+
Now, why this much pain just to set up a constraint ? Well, I need to keep all text fields across my 15+ domains, consistent in terms of characters they accept. Since this is business driven requirement, I need to keep it configurable, so that we can remove/add any new chars at any time, without the risk of touching too many domain classes for the sake of integrity. In addition to that, I want to use the available regex in other Service classes as well.
Now, this implementation works well in run-app, production & test-app integration:
Only problem is with Unit tests cases. What I can understand is, that such dependencies, Grails won't be able to inject automatically, in a unit-test env.
Can we mock & add Configuration class using metaClass manipulation ? I have tried but failed.(read: I am not aware how mocking for Static classes work and how to add them to metaClass)
Or, if there's another way to implement such kind of concept ?
Many Thnx
To avoid repeating the constraint across multiple domain classes, you could use either a shared constraint or a global constraint.
If you use a global constraint, then to enable you to access the regex from a service class, store the regex in a separate config param.
Config.groovy
allowed.text.chars='bigLongRegex'
grails.gorm.default.constraints = {
subject matches: allowed.text.chars
}
Service Class
class MyService {
GrailsApplication grailsApplication
void something() {
String regex = grailsApplication.config.allowed.text.chars
}
}
If you want to write a unit test that tests the domain class' constraint remember to add the #Mock annotation, e.g.
#Mock([DomainClass])
class DomainClassTests {
void testConstraint() {
// test code goes here
}
}

Instrumented (by cobertura) #Decorator bean could not validated by OpenEJB for unit testing

In order to get code coverage report, i instrument the #Decorator bean by cobertura maven plugin.
When running my unit test in OpenEJB container. The container reports some error during start up (new initial context).
Caused by: org.apache.webbeans.exception.WebBeansConfigurationException: Decorator : MyDecorator, Name:null, WebBeans Type:DECORATOR, API Types:[org.apache.commo
ns.configuration.Configuration,net.sourceforge.cobertura.coveragedata.HasBeenInstrumented,org.apache.commons.configuration.AbstractConfiguration,MyDecorator,org.apache.commons.configuration.event.EventSource,java.lang.Object], Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.inject.Default] delegate at
tribute must implement all of the decorator decorated types, but decorator type interface net.sourceforge.cobertura.coveragedata.HasBeenInstrumented is not assignable from deleg
ate type of interface org.apache.commons.configuration.Configuration
Details:
I have one Decorator to be unit tested.
Something like
import org.apache.commons.configuration.AbstractConfiguration;
import org.apache.commons.configuration.Configuration;
#Decorator
public class MyDecorator extends AbstractConfiguration {
#Inject
#Delegate
private Configuration conf;
.....
}
After cobertura instrumented it, the code is like below:(I uncompile it)
import net.sourceforge.cobertura.coveragedata.HasBeenInstrumented;
#Decorator
public class MyDecorator extends AbstractConfiguration
implements HasBeenInstrumented
{
#Inject
#Delegate
private Configuration conf;
.....
}
As you can see, cobertura add one more interface for my decorator.
When OpenEJB load and deploy this instrumented class, a error is reported:
Caused by: org.apache.webbeans.exception.WebBeansConfigurationException: Decorator : MyDecorator, Name:null, WebBeans Type:DECORATOR, API Types:[org.apache.commo
ns.configuration.Configuration,net.sourceforge.cobertura.coveragedata.HasBeenInstrumented,org.apache.commons.configuration.AbstractConfiguration,MyDecorator,org.apache.commons.configuration.event.EventSource,java.lang.Object], Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.inject.Default] delegate at
tribute must implement all of the decorator decorated types, but decorator type interface net.sourceforge.cobertura.coveragedata.HasBeenInstrumented is not assignable from deleg
ate type of interface org.apache.commons.configuration.Configuration
The error log say that the #Decorator and the #Delegate should implement the same types.
But after instrument, the to be tested class has one more interface.
Then i try to instrument the org.apache.commons.configuration.AbstractConfiguration and org.apache.commons.configuration.Configuration. (by instrument the commons-configuration-1.9.jar by cobertura command line)
And modify my code like:
#Decorator
public class MyDecorator extends AbstractConfiguration {
#Inject
#Delegate
private AbstractConfiguration conf;
.....
}
//I use AbstractConfiguration instead of Configuration, because the Configuration is an //interface which could not be instrumented.
After all of this,the problem is solved.
But it is not a good way to do this.
The root cause is maven cobertura plugin identify the class file is instrumented by adding an interface to the original class, i works for most of the cases.
But not for a #Decorator bean which running in an container.
Should i create an comments for maven-cobertura-plugin org?
Any one has some suggestion on how to unit test #Decorators.And easy to get coverage report?
May be my unit test is not implement in the good way, maybe the openejb is not good for this?
Normally how do you unit test your #Decorators?
Cobertura does not instrument interfaces. It is recommended the non-instrumented classes go in the classpath after the instrumented classes for that reason.
So when instrumenting, compile first with maven normally, then place yourself in the directory where the sourcecode of the classes you want to instrument exists, and then run the following command : mvn cobertura:instrument.
This will make cobertura instrument all the classes, and maven will automatically add the files not instrumented. the instrumented code will be at ".\target\generated-classes\cobertura".
You'll need to run the 'jar -cvf [name-of-jar].jar *', then you'll get your instrumented jar.