I know there's a lot out there about this particular topic, however I can't quite find anyone who has stumbled across my issue, and hopefully someone can explain this to me.
I have a Domain where I use the injected grailsApplication's dynamic method 'isDomainClass' in the equals method:
#Override
public boolean equals(Object obj) {
if(!grailsApplication.isDomainClass(obj.getClass())) { return false }
...
}
This works fine, and to unit test this i do:
#Mock([MyDomain])
...
def mockGApp
void setUp() {
mockGApp = new Object()
mockGApp.metaClass.isDomainClass = { obj -> true }
}
...
void testSomething() {
def myDomain = new MyDomain()
myDomain.grailsApplication = mockGApp
....
}
And when I run this with test-app -unit (on command line or in STS) it passes just fine.
I then ave an integration test that uses that domain (no mocking this time) and that again runs fine when ran with test-app -integration (either on the command line or in STS)
However if i run 'test-app' so it does both at once, I get a MissingMethodException: no method signature isDomainClass exists with parameters (java.lang.Class) ... and all that jazz.
On investigating it with println's in the service I'm testing in the tests, in the integration portion of the testing, before the equals method of my domain class is called, I can quite happily call grailsApplication.isDomainClass() and get the desired affect. However when the code steps into the domain's equals function the isDomainClass() method no longer exists, despite the grailsApplication object referring to the same object which is referenced in the service and has the dynamically added method.
It appears that the dynamic methods that grails adds to this class are not being injected when its called within the domain's methods but are getting injected within the service. And more bizarrely this only happens if the integration tests follow the unit tests. If done separately, no problemo...
Where does this pollution stem from? IS there any way to solve it?
P.S. using Grails 2.1.0
You have to remove the class you modified from metaClassRegistry in the destroy method (i.e.after test case runs). See below:
#After
void destroy() {
GroovySystem.metaClassRegistry.removeMetaClass(MyDomain.class)
}
Related
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
}
}
Have a #PostConstruct in the service to ensure that the dependencies have been set up. Dependencies are set in resources.groovy. Unit test fails on #PostConstruct asserts. Tried setting up the dependencies manually in setUpSpec to no avail. Even without a #TestFor, ServiceUnitTestMixin kicks in and merrily chokes on #PostConstruct.
Opened a defect GRAILS-11878 which was closed promptly with an advice to use #FreshRuntime and doWithSpring. If they actually bothered to try, they'd have gotten the following error:
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'grails.spring.BeanBuilder$ConfigurableRuntimeBeanReference$WrappedPropertyValue#2cce10bc' with class 'grails.spring.BeanBuilder$ConfigurableRuntimeBeanReference$WrappedPropertyValue' to class 'java.util.Collection'
Service under test:
#Transactional
class MovieRipIndexService {
Collection<String> genres
Collection<String> includes
#PostConstruct
void postConstruct() {
notEmpty(genres as Collection, 'Genres must not be null or empty.')
notEmpty(includes as Collection, 'Includes must not be null or empty.')
}
}
Test:
#FreshRuntime
#TestFor(MovieRipIndexService)
class MovieRipIndexServiceSpec extends Specification {
def doWithSpring = {
serviceHelper(ServiceHelper)
service.genres = serviceHelper.genres
service.includes = serviceHelper.includes
}
}
Spring support in unit tests is rather minimal, and the ApplicationContext that's active doesn't really go through any of the lifecycle phases that it would in a running app, or even during initialization of integration tests. You get a lot of functionality mixed into your class when using #TestFor and/or #Mock, but it's almost entirely faked out so you can focus on unit testing the class under test.
I tried implementing org.springframework.beans.factory.InitializingBean just now and that worked, so you might get further with that.#Transactional will also be ignored - the "database" is a ConcurrentHashMap, so you wouldn't get far with that anyway.
If you need real Spring behavior, use integration tests. Unit tests are fast and convenient but only useful for a fairly limited number of scenarios.
I have a command object with a couple of static methods which access other domain objects.
static def isAValidSerial(String serialReference) {
return InventoryMaster.partSerialReferenceList(null, serialReference).size() > 0
}
This method is called by the validation constraints on the command object.
In a unit test I mock this behavior.
TransactionDetailCommand.metaClass.static.isAValidSerial = { String a -> println "mocked method called"; true }
before invoking some validation:
obj.validate(['serialReference'])
However this is throwing an exception where it didn't with 2.2.0.
The error is:
java.lang.IllegalStateException: Method on class [com.myStuff.MyClass] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly.
Despite the mocking when it's called from the validator it appears to be trying to invoke the real method and not the mock. If I put an explicit println before the obj.validate() it correctly prints the test text from the mocked method and returns the mocked value. This worked on 2.2 but now fails. I didn't used the grails update command. I created a new project and copied stuff to it. I've found various tips including removing the forked JVM stuff from the build config but nothing seems to work.
Anyone any ideas? Thanks.
I finally managed to get this working. Firstly I had to explicitly declare the collaborating class (InventoryMaster) within the #Mock annotation - on 2.2.n this wasn't required. Also when invoking mocked static methods from my validator I had to explicitly qualify the static call .. So what used to look like
if (!(cmdObj.transactionType.transactionIsAReceipt() || isAValidSerial(serialReference))) {
return 'TransactionDetailCommand.serialReference.not.found'
}
and work under 2.2.n had to be converted to ..
if (!(cmdObj.transactionType.transactionIsAReceipt() || TransactionDetailCommand.isAValidSerial(serialReference))) {
return 'TransactionDetailCommand.serialReference.not.found'
}
which kinda makes sense as I previously mocked the isAValidSerial using
TransactionDetailCommand.metaClass.static.isAValidSerial = {a -> println "running mock isAValidSerial -> true"; true }
Maybe that was 2.2.n being lax .. Anyway, my tests now work again !
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 :).
This is a tough one because not too many people use Pex & Moles or so I think (even though Pex is a really great product - much better than any other unit testing tool)
I have a Data project that has a very simple model with just one entity (DBItem). I've also written a DBRepository within this project, that manipulates this EF model. Repository has a method called GetItems() that returns a list of business layer items (BLItem) and looks similar to this (simplified example):
public IList<BLItem> GetItems()
{
using (var ctx = new EFContext("name=MyWebConfigConnectionName"))
{
DateTime limit = DateTime.Today.AddDays(-10);
IList<DBItem> result = ctx.Items.Where(i => i.Changed > limit).ToList();
return result.ConvertAll(i => i.ToBusinessObject());
}
}
So now I'd like to create some unit tests for this particular method. I'm using Pex & Moles. I created my moles and stubs for my EF object context.
I would like to write parametrised unit test (I know I've first written my production code, but I had to, since I'm testing Pex & Moles) that tests that this method returns valid list of items.
This is my test class:
[PexClass]
public class RepoTest
{
[PexMethod]
public void GetItemsTest(ObjectSet<DBItem> items)
{
MEFContext.ConstructorString = (#this, name) => {
var mole = new SEFContext();
};
DBRepository repo = new DBRepository();
IList<BLItem> result = repo.GetItems();
IList<DBItem> manual = items.Where(i => i.Changed > DateTime.Today.AddDays(-10));
if (result.Count != manual.Count)
{
throw new Exception();
}
}
}
Then I run Pex Explorations for this particular parametrised unit test, but I get an error path bounds exceeded. Pex starts this test by providing null to this test method (so items = null). This is the code, that Pex is running:
[Test]
[PexGeneratedBy(typeof(RepoTest))]
[Ignore("the test state was: path bounds exceeded")]
public void DBRepository_GetTasks22301()
{
this.GetItemsTest((ObjectSet<DBItem>)null);
}
This was additional comment provided by Pex:
The test case ran too long for these inputs, and Pex stopped the analysis. Please notice: The method Oblivious.Data.Test.Repositories.TaskRepositoryTest.b__0 was called 50 times; please check that the code is not stuck in an infinite loop or recursion. Otherwise, click on 'Set MaxStack=200', and run Pex again.
Update attribute [PexMethod(MaxStack = 200)]
Question
Am I doing this the correct way or not? Should I use EFContext stub instead? Do I have to add additional attributes to test method so Moles host will be running (I'm not sure it does now). I'm running just Pex & Moles. No VS test or nUnit or anything else.
I guess I should probably set some limit to Pex how many items should it provide for this particular test method.
Moles is not designed to test the parts of your application that have external dependencies (e.g. file access, network access, database access, etc). Instead, Moles allows you to mock these parts of your app so that way you can do true unit testing on the parts that don't have external dependencies.
So I think you should just mock your EF objects and queries, e.g., by creating in-memory lists and having query methods return fake data from those lists based on whatever criteria is relevant.
I am just getting to grips with pex also ... my issues surrounded me wanting to use it with moq ;)
anyway ...
I have some methods similar to your that have the same problem. When i increased the max they went away. Presumably pex was satisfied that it had sufficiently explored the branches. I have methods where i have had to increase the timeout on the code contract validation also.
One thing that you should probably be doign though is passing in all the dependant objects as parameters ... ie dont instantiate the repo in the method but pass it in.
A general problem you have is that you are instantiating big objects in your method. I do the same in my DAL classes, but then i am not tryign to unit test them in isolation. I build up datasets and use this to test my data access code against.
I use pex on my business logic and objects.
If i were to try and test my DAL code id have to use IOC to pass the datacontext into the methods - which would then make testing possible as you can mock the data context.
You should use Entity Framework Repository Pattern: http://www.codeproject.com/KB/database/ImplRepositoryPatternEF.aspx