I'm testing a controller and there I defined an action which uses a value from the requestobject.
How can I mock the request object in an integration test?
I know that integration tests don't run in an Servlet, so there is no Requestobject, but how do I obtain it?
Quickest thing is to mock needed methods using Map coercion:
myController.request = [ getHeader: { -> '0' } ]
(that link also includes Expando sample).
If you need extensive Request usage, try functional-test plugin.
Related
I am writing grails integration tests which call out to a controller which call a service which calls another service which calls another service.
Controller -> ServiceA.method1() -> ServiceB.method2() -> ServiceC.method3()
the last method in the last service to be called (ServiceC.method3()) makes a call to the outside world (another JVM) and returns a result, which I want to mock out for my integration test. So I am still testing the chain up to and back from that particular service method.
I was reading up on mocking in grails but it seems that it is only possible in unit testing.
Any tips how to progress this one?
Use the metaClass to override a method's functionality. I do this all the time in my integration tests as my way to mock.
So in your test method do something like this (note that the method arg types must match exactly with the real method):
controller.serviceA.serviceB.serviceC.metaClass.method3 = { Args args ->
// do whatever you want here, set flags to indicate method called,
// assert args, declare return types, etc
// return 'mocked' result
}
Make sure in your integration test tear down method you reset the metaClass of this service otherwise all your other int tests will have the same definition:
controller.serviceA.serviceB.serviceC.metaClass = null
I was reading up on mocking in grails but it seems that it is only
possible in unit testing.
That's certainly not true.
You could use all ways of mocking that are available in Groovy in both unit and integration tests.
With mocking using Map coercion, it can be this easy:
controller.serviceA.serviceB.serviceC = [method3: {return 'MockValue'}] as ServiceC
I have a method that is declared as so:
public ActionResult Request(Request request)
{
The method is called using JavaScript, but a string is passed in. The deserialization happens automatically.
Now I want to unit test this mimicking what the JavaScript would be passing in, which is a string. How do I unit test using a string instead of Request? When I create my unit test, it expects me to pass in the deserialized type which isn't the end of the world, but it would be nice if I could just copy the string request that gets sent in from the client and test with that.
Is this even possible... to force the automatic deserialization that normally happens?
TrackController c = new TrackController();
c.Request(jsonString);
Deserializing the json into your concrete model object is really the responsibility of the MVC model binder, so I don't think that should be included in the unit test of the controller action.
However I do see some value in testing that you are creating your requests correctly, but I think this is a better fit for an integration test.
You could potentially make http requests to your website directly, which would validate if you're passing correct json to your action.
See more here:
POSTing JSON to URL via WebClient in C#
so I think I'm perhaps not fully understanding how you would use an IOC container for doing Integration tests.
Let's assume I have a couple of classes:
public class EmailComposer : IComposer
{
public EmailComposer(IEmailFormatter formatter)
{
...
}
...
public string Write(string message)
{
...
return _formatter.Format(message);
}
}
OK so for use during the real application (I'm using autofac here) I'd create a module and do something like:
protected override void Load(ContainerBuilder containerBuilder)
{
containerBuilder.RegisterType<HtmlEmailFormatter>().As<IEmailFormatter>();
}
Makes perfect sense and works great.
When it comes to Unit Tests I wouldn't use the IOC container at all and would just mock out the formatter when I'm doing my tests. Again works great.
OK now when it comes to my integration tests...
Ideally I'd be running the full stack during integration tests obviously, but let's pretend the HtmlEmailFormatter is some slow external WebService so I decide it's in my best interest to use a Test Double instead.
But... I don't want to use the Test Double on all of my integration tests, just a subset (a set of smoke-test style tests that are quick to run).
At this point I want to inject a mock version of the webservice, so that I can validate the correct methods were still called on it.
So, the real question is:
If I have a class with a constructor that takes in multiple parameters, how do I make one of the parameters resolve to a an instance of an object (i.e. the correctly setup Mock) but the rest get populated by autofac?
I would say you use the SetUp and TearDown (NUnit) or ClassInitialize and ClassCleanup (MSTest) for this. In initialize you register your temporary test class and in cleanup you restore to normal state.
Having the DI container specify all the dependencies for you has the benefit of getting an entire object graph of dependencies resolved. However if there's a single test in which you want to use a different implementation I would use a Mocking framework instead.
So I have a grails domain class:
class Message
{
Inbox inbox
Boolean hasBeenLogicallyDeletedByRecipient
...
static belongsTo = [
inbox:Inbox,
...
]
static constraints = {
hasBeenLogicallyDeletedByRecipient(nullable:false)
...
}
}
I would like to use a dynamic finder as follows:
def messages = Message.findAllByInboxAndHasBeenLogicallyDeletedByRecipient(
inbox, false, [order:'desc',sort:'dateCreated'])
This works fine running a unit test case in STS 2.6.0.M1 against grails 1.2.1;
Spinning up the web app, it fails because of the By in hasBeenLogicallyDeletedByRecipient (I'm guessing it has confused the dynamic finder parsing when building up the query).
I can use a criteria builder which works in the app:
def messages = Message.withCriteria {
and {
eq('inbox', inbox)
eq('hasBeenLogicallyDeletedByRecipient', false)
}
order('dateCreated', 'desc')
}
But since withCriteria is not mocked, it doesn't immediately work in unit tests, so I could add the following to the unit test:
Message.metaClass.static.withCriteria = { Closure c ->
...
}
Is the criteria/unit test mocking the best/accepted approach? I don't feel completely comfortable with mocking this, as it sidesteps testing the criteria closure.
Ideally, I'd rather use the dynamic finder - is there a succinct way to make it work as is?
If there is no way around it, I suppose the field name could be changed (there is a reason why I don't want to do this, but this is irrelevant to the question)...
UPDATE:
Here's the stacktrace when I try to use findAllByInboxAndHasBeenLogicallyDeletedByRecipient() inside the app - notice how it appears to get the last By and treat everything else between it and findAll as a property. i grazed on http://grails.org/OperatorNamesInDynamicMethods but it doesn't mention anything about By being verboten.
org.codehaus.groovy.grails.exceptions.InvalidPropertyException: No property found for name [byInboxAndHasBeenLogicallyDeleted] for class [class xxx.Message]
at xxx.messages.yyyController$_closure3.doCall(xxx.messages.yyyController:53)
at xxx.messages.yyyController$_closure3.doCall(xxx.messages.yyyController)
at java.lang.Thread.run(Thread.java:662)
Testing the database querying is really an Integration test, not a unit test. Is your test in /test/unit or /test/integration ? - I'd expect the 'withCriteria' to be fully functional in the integration tests, but not in unit tests.
From the grails docs ( http://grails.org/doc/latest/ ), section 9.1:
Unit testing are tests at the "unit"
level. In other words you are testing
individual methods or blocks of code
without considering for surrounding
infrastructure. In Grails you need to
be particularity aware of the
difference between unit and
integration tests because in unit
tests Grails does not inject any of
the dynamic methods present during
integration tests and at runtime.
I'd like to test a "withCriteria" closure and am not sure how to go about it. I see how to mock out the withCriteria call, but not test the code within the closure. When running the test that executes the "withCriteria", I keep getting a MissingMethodException, even though the code runs fine under the normal flow of execution. Any ideas?
Thanks!
Steve
I wouldn't go that route. Instead I'd move the query into the domain class as a static finder method and test it directly in an integration test with real data. Then you can easily mock the helper method when it's called in a controller or service test.
class YourDomainClass {
...
static List<YourDomainClass> findFooBar() {
YourDomainClass.withCriteria {
...
}
}
}
Then in a unit test:
def results = [instance1, instance2, instance3]
YourDomainClass.metaClass.static.findFooBar = { -> results }
This way you test that the query works against the in-memory database in an integration test but it's easy to mock it in unit tests.
Further to Burt's answer, check out named queries as described here:
http://blog.springsource.com/2010/05/24/more-grails-1-3-features/
You can then mock the property/method access in your unit tests as described by Burt.
Since nobody mentioned the option to create a DSL to run other DSLs here's a full disclosure of this method. I use it quite often with very good results.
Groovy/Grails testing DSLs
There's no mock implementation for Hibernate criteria at the present time. You'll need to use integration tests. However, Burt's recommendation of making this a static finder method is a good one for code organization. You should also look at named queries, described at http://www.grails.org/1.2+Release+Notes, for a nice syntax for this.