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)
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 don't know whether to use unit or integration tests for what I am wanting to test in my Grails 2.2.3 application. I want to run some tests against like this:
#TestFor(Student)
#Mock(Student)
class StudentTests {
void testFoundStudent() {
def s = Student.findById(myId)
assert s != null
assert s.firstName = 'Grant'
assert s.lastName = 'McConnaughey'
}
}
This is going to require the use of our test database, so would that make it an integration test? When I run this code as a unit test it fails at assert s != null. Which means it isn't using our database, because it SHOULD find a student with that ID.
In Grails unit test you can test domain class interactions using Gorm and behind the scene Grails will use in-memory database(an implementation of a ConcurrentHashMap) to mimic this behavior here. So yes you get null because that student does not exist in in-memory database and you need to insert that data first.
Student.findOrSaveWhere (firstName: 'Grant',lastName : 'McConnaughey')
In your example, if the intention is to test the existence of that data you need to use integration test and connect it to your database using datasource.groovy , which is really not a good idea unless you have a good reason to test your data.
If you are trying to test def s = Student.findById(myId) again that is not adding any value as that is Grails dynamic finder and you probably need to trust the framework you are using.
However, in general
Unit tests are typically run without the presence of physical
resources that involve I/O such databases, socket connections or
files link
I hope this helps
I have this simple method which calls the TFS (Team foundation server) API to get WorkItemCollection object. I have just converted in to an entity class and also added it in cache. As you can see this is very simple.
How should i unit test this method. Only the important bit it does is calls TFS API. Is it worth testing such methods? If yes then how should we test it?
One way I can think is I can mock call to Query.QueryWorkItemStore(query) and return an object of type “WorkItemCollection” and see finally this method converts “WorkItemCollection” to List. And check if it was added to cache or not.
Also as I am using dependency injection pattern her so I am injecting dependency for
cache
Query
Should I only pass dependency of mocked type (Using MOQ) or I should pass proper class type.
public virtual List<Sprint> Sprint(string query)
{
List<Sprint> sprints =
Cache.Get<List<Sprint>>(query);
if (sprints == null)
{
WorkItemCollection items =
Query.QueryWorkItemStore(query);
sprints = new List<Sprint>();
foreach (WorkItem i in items)
{
Sprint sprint = new Sprint
{
ID = i.Id,
IterationPath = i.IterationPath,
AreaPath = i.AreaPath,
Title = i.Title,
State = i.State,
Goal = i.Description,
};
sprints.Add(sprint);
}
Cache.Add(sprints, query,
this.CacheExpiryInterval);
}
return sprints;
}
Should I only pass dependency of mocked type (Using MOQ) or I should pass proper class type.
In your unit tests, you should pass a mock. There are several reasons:
A mock is transparent: it allows you to check that the code under test did the right thing with the mock.
A mock gives you full control, allowing you to test scenarios that are difficult or impossible to create with the real server (e.g. throw IOException)
A mock is predictable. A real server is not - it may not even be available when you run your tests.
Things you do on a mock don't influence the outside world. You don't want to change data or crash the server by running your tests.
A test with mocks is faster. No connection to the server or real database queries have to be made.
That being said, automated integration tests which include a real server are also very useful. You just have to keep in mind that they will have lower code coverage, will be more fragile, and will be more expensive to create/run/maintain. Keep your unit tests and your integration tests separate.
edit: some collaborator objects like your Cache object may also be very unit-test friendly. If they have the same advantages as that of a mock that I list above, then you don't need to create a mock. For example, you typically don't need to mock a collection.
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