Grails Functional Testing Plugin and RESTful Tests - grails

I just grabbed the latest version of the functional testing plugin and it's focus, at least from the docs, has changed a bit. This is not a bad thing. The HtmlUnit integration is nice. But now, there isn't anything in the docs about RESTful testing of web services. However, what I used to do with functionaltestplugin.FunctionalTestCase still works, which is great.
For example:
void testCertifyEmployerCertifierNotFound() {
post('/employerCertification/certifyEmployer') {
headers['Content-Type'] = 'application/json'
body {
"""
{
'employerName': 'ACME',
'certifierExteralId': '1234556',
'certifyingUserId': '123445'
}
"""
}
}
assertStatus 200
assertContentType "application/json"
def model = this.response.contentAsString
def map = JSON.parse(model)
assertFalse(map.success)
assertNotNull(map.errorCode)
assertTrue(map.errorCode == EmployerCertificationService.ERROR_RESPONSE.CERTIFIER_NOT_FOUND.toString())
}
Is this plugin still the "defacto" plugin to use for functional web service testing and is my approach above still valid?

if your target is testing REST request/response I suggest you to use rest client builder plugin. You don't need complex browser-simul plugins. Use it is very simple in just two steps after installing it:
add event to manage functional tests in scripts/_Events.groovy: this is a system grail file used to hook some events at runtime. Just copy and paste this snippet:
eventAllTestsStart = {
if (getBinding().variables.containsKey("functionalTests")) {
functionalTests << "functional"
}
}
Now you can create functional tests in test/functional folder, rememeber to ends filename with Spec, grails will not find any tests if you forget this.
This is an example:
import grails.plugins.rest.client.RestBuilder
import spock.lang.Specification
class AuthenticationSpec extends Specification {
String baseUrl = "http://localhost:8080/grouply-backend"
void "test login wrong credentials"() {
given:
RestBuilder restBuilder = new RestBuilder()
when: "sending wrong credential"
def response = restBuilder.post("${baseUrl}/auth/login") {
json {
username = 'foo'
password = 'bar'
}
}
then: "authentication http error should happen"
response.status == 401
}
}
run tests with $ grails test-app functional:

I have just tried to use both functional testing plugin and webtest plugin with almost-current Grails 2.4.2 and I am sad to report that they are both borked. :(
Functional testing plugin has been practically abandoned for at least 9 months now. On December 2013 a critical bug that makes all of tests written using this plugin not working has been reported. There was no response from plugin developer regarding it up to the day I am writing this. And as this developer, Marc Palmer has switched to iOS development and consultancy in August 2014 I don't believe this bug will ever be resolved.
Webtest plugin has been last updated more than 3 years ago and it "requires Grails 1.2.RC2+". I run into ugly error of missing webtest.jar when running it and it looks like this plugin just haven't been updated to current Grails version. Also its syntax is not very Groovy-like and not nice.
Fortunately Geb integration for Grails plugin is supposed to work with current Grails versions. :) In fact in does only work with Grails 2.3.1+, as of writing these words has been last time updated in June 2014 and it's example tests project have been updated to Grails 2.4.3, release just a few days ago already, so it is very up-to-date. However I haven't used this project yet. Also looking at is's example code I am not sure it the best choice for RESTful API testing - it's more of a GUI web application testing tool..

Although is probably not very "grails style" i guess it should be possible to start up the whole stack with the spring context and run integration rest tests using apache HttpClient.

Related

Unable to resolve class AsyncHttpBuilder

Using Grails 1.3.9
buildConfig.groovy
compile "org.grails.plugins:async-http-builder"
code:
AsyncHttpBuilder client = new AsyncHttpBuilder()
Promise<HttpClientResponse> p = client.post("http://someuUrl") {
contentType 'application/json'
json {
receiver number
message content
sender sender
}
}
p.onComplete { HttpClientResponse resp ->
println(resp);
}
I get the error in the topic title. What am I missing here?
A rather general steps for checking problems with missing plugins
Check if you have mavenRepo "https://repo.grails.org/grails/plugins" in repositories { in BuildConfig.groovy
Provide plugin version, so instead of "org.grails.plugins:async-http-builder" try "org.grails.plugins:async-http-builder:1.0.0"
Try grails refresh-dependencies in the terminal
Looking at the commit dates, it looks like a fresh plugin (<1 year old), so it's possible it works only with newer Grails versions (2+/3+).
The documentation states
Note that this client does not require Grails itself, and can easily be used standalone or as an independent HTTP client.
(...)
To get started with the HTTP client you should declare a dependency on the grails-http-client project in your build.gradle file:
compile "org.grails:http-client:VERSION"
So I would probably just try that, as the plugin might not play well with your old Grails version.

Grails 3 Quartz plugin: Job doesn't start

I am trying to do a simple background job in Grails. I just want stuff to happen every 30 seconds or so.
I am using Grails 3.1.3
I've added Quartz to my dependencies:
compile "org.grails.plugins:quartz:2.0.1"
Then I've run a compile and restarted the grails CLI. Now I created a Job via create-job. It looks like this:
package htwp
class UserSyncJob {
static triggers = {
simple repeatInterval: 5000l // execute job once in 5 seconds
}
def execute() {
println ("?")
log.error("??!")
throw new Error("JOB WHERE ARE YOU");
}
}
Nothing happens when I start the server via run-app. Nothing printed, no errors either.
What am I doing wrong?
I checked issues of quartz plugin for Grails project and found this issue and this issue.
Just upgrade as I said earlier in comment to the newest realese of plugin.

Grails auto-reloading new controller actions

I've
created new Grails 2.4.3 project
created TestController
set grails.reload.enabled = true in BuildConfig.groovy
run application with grails -reloading run-app
My controller action code:
def index() {
render "test"
}
When I change the string test to test2- I see in console (in Eclipse):
..................
|Compiling 1 source files
And after reloading page I see test2 - ok.
But when I try to add new method:
def test3() {
render "test3"
}
I see:
Why? Why there isn't even the url?
Example - action does't exist:
Interesting thing is - when I create a whole new controller the index action of the newly created controller works...
EDIT
After a while I decided to go with spring-boot and as a matter of fact - there it's not working either. I think that springloaded is the issue here because it doesn't pick up added new method in #Controller
I've asked the same question on github repo.
It seems that latest spring-loaded SNAPSHOT is working fine.
But it must be integrated into Grails - maybe in the next release unfortunately :(
Solution that works for me:
1) Versions:
IDE: Intellij IDEA 14.1.3
JDK: jdk1.7.0_25
GRAILS: 2.5.0
2) On BuildConfig.groovy:
grails.reload.enabled = true
grails.project.fork = [
test: false,
run: false,
]
3) Originally, my code was compiled on grails 2.4.4, so I upgraded to 2.5.0. I had no problems with the version change with plugins or anything. My guess is this works because it uses later versions of spring-loaded. Steps:
set-grails-version 2.5.0
clean
delete directory work (just to be sure, I don't really know if this is good practice)
compile and/or go to number 4
4) Debug Idea with this configuration: run-app -reloading
Works perfect, no forked debug, reloading enabled, no console error after reload and all breakpoints working even after code changes!
I took the liberty of reporting this issue to Grails.

Spock Integration Test fails when run with other integration tests-succeeds in isolation using integration:spock

I am adding a first spock integration test to an existing set of tests for a grails 2.1.1 application. The test runs and tests pass when run using:
grails test-app integration:spock CreditServiceSpec
(Yes, everything is in the default package - fixing this is a ton of work that will not be approved...file under technical debt.)
However, when I run all the tests (grails test-app), unit test pass, spock unit tests pass, integration tests pass, but I get the following failure for spock integration:
| Completed 818 integration tests, 0 failed in 104001ms
| Running 1 spock test...
| Failure: CreditServiceSpec
| groovy.lang.GroovyRuntimeException: failed to invoke constructor: public org.codehaus.groovy.grails.test.support.GrailsTestAutowirer(org.springframework.context.ApplicationContext) with arguments: [] reason: java.lang.IllegalArgumentException
at grails.plugin.spock.IntegrationSpec.$spock_initializeSharedFields(IntegrationSpec.groovy:33)
| Completed 0 spock test, 0 failed in 33ms
| Tests PASSED - view reports in /Users/*/projects/GrailsPlugins/DomainServices/target/test-reports
I get the exact same exception whether I run the full test I built or the following, very strip down example:
import grails.plugin.spock.IntegrationSpec
class CreditServiceSpec extends IntegrationSpec {
def setup() {}
def cleanup() {}
public void "sample"() {
setup:"Nothing to do here."
expect:"This is the truest of truths..."
true == true
}
}
I did crack open IntegrationSpec and looked at line 33:
#Shared private autowirer = new GrailsTestAutowirer(applicationContext)
But determining how/why the applicationContext is not being passed in properly is beyond me and, perhaps, is the thrust of my question.
Has anyone encountered this kind of behavior and found a way to get spock integration to play nice with other tests? Thanks.
It looks like Grails 2.1.1 had several issues with Spock tests in the Integration scope. Jeff's comment and Peter's in particular sound like the issue you were having; basically the ApplicationHolder was null or an empty list.
The parent task lists Grails 2.2.5 as the fix version. Any chance you can upgrade to that (or some even later version) and see if the problem persists?
There have also been cases where a simple grails clean has fixed issues like this.
I had a problem with the exact same symptom.
I was using the BuildTestData plugin and used the #Build annotation in a IntegrationSpec, but using the #Build with use a transformation wich extended the #TestFor transformation which is incompatible with the Intengration runtime.
So just remove the #Build annotations and it will run.

MvcIntegrationTestFramework or an alternative updated for ASP.NET MVC 3

I'm interested in using Steve Sanderson’s MvcIntegrationTestFramework or a very similar alternative with ASP.NET MVC 3 Beta.
Currently when compiling MvcIntegrationTestFramework against MVC 3 Beta I get the following error due to changes in MVC:
Error 6
'System.Web.Mvc.ActionDescriptor.GetFilters()' is obsolete: '"Please call System.Web.Mvc.FilterProviders.Providers.GetFilters() now."' \MvcIntegrationTestFramework\Interception\InterceptionFilterActionDescriptor.cs Line 18
Questions
Can anybody provide the MvcIntegrationTestFramework working for ASP.NET MVC 3 Beta?
--- and / or ---
Are there similar alternatives you would recommend?
EDIT #1: Note I have e-mailed Steve the creator of MvcIntegrationTestFramework, also hoping for some feedback there.
EDIT #2 & #3: I have received a message from Steve. Quoted for your reference:
I haven't needed to use that project with MVC 3, so sorry, I don't have an updated version of it. As far as I'm aware it should be possible to update it to work on MVC 3, but you'd need to figure that out perhaps by inspecting the MVC 3 source code to notice any changes in how actions, filters, etc are invoked now. If you do update it, and if you decide to adopt it as an ongoing project (e.g., putting it on Github or similar), let me know and I'll post a link to it! (Thanks Steve!)
EDIT #4: Honestly had a quick stab at using System.Web.Mvc.FilterProviders.Providers.GetFilters() didn't get anywhere fast and simply adding the [Obsolete] found that there was an error in the internals of the MVC requests. Anybody else had a dabble?
EDIT #5: Please comment if you are using an alternative Integration Test Framework with MVC 3.
Have a look at my fork:
https://github.com/JonCanning/MvcIntegrationTestFramework/
I realize this is not the answer you're looking for but Selenium or Watin may be of use to you as an alternative to the Integration Test Framework.
Selenium will let you record tests as nUnit code so you can integrate with your existing test projects etc. Then your test can validate the DOM similarly to the Integration Test Framework. The advantage is Selenium tests can be executed with various different browsers.
Key caveat is that Selenium needs your app to be deployed on a web server, not sure if that's a show stopper for you.
I thought I would share my experiences with using MvcIntegrationTestFramework in an ASP.NET MVC 4 project. In particular, the ASP.NET MVC 4 project was a Web Role for a Windows Azure Cloud Service.
Although the example project from Jon Canning's fork worked for me (although I did change the System.Web.Mvc assembly from 3.0.0.0 to 4.0.0.0, which required a bunch of editing in the web.config file to get the tests to run and pass), I got an error whenever I tried to run the same tests against an Azure ASP.NET MVC 4 Web Role project. The error was:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
The inner exception was:
System.InvalidOperationException: This method cannot be called during the application's pre-start initialization phase.
I started wondering how an Azure Web Role project based on ASP.NET MVC 4 was different to a normal ASP.NET MVC 4 project, and how such a difference would cause this error. I did a bit of searching on the web but didn't come across anybody trying to do the same thing that I was doing. Soon enough I managed to realise that it was to do with the Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener. Part of the role of this class seems to be to ensure that the web role is running in a hosted service or the Development Fabric (you'll see a message to this effect if you switch the startup project from the cloud service project to the web role project inside a cloud service solution, and then try to debug).
The solution? I removed the corresponding listener from the Web.config file of my Web Role project:
<configuration>
...
<system.diagnostics>
<trace>
<listeners>
<!--Remove this next 'add' element-->
<add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="AzureDiagnostics"> <filter type="" /> </add>
</listeners>
</trace>
</system.diagnostics>
...
</configuration>
I was then able to run integration tests as normal against my Web Role project. I did, however, add the listener to the Web.Debug.config and Web.Release.config transformation files so that everything was still the same for normal deploying and debugging.
Maybe that will help somebody looking to use the MvcIntegrationTestFramework for Azure development.
EDIT
I just realised that this solution might be a bit of a 'hack' because it might not let you do integration testing on application code that relates to Azure components (e.g. the special Azure caching mechanisms perhaps). That said, I haven't come across any issues to do with this yet, although I also haven't really written that many integration tests yet either...
I used Jon Canning's updated version (https://github.com/JonCanning/MvcIntegrationTestFramework/) and it solved my problem very well for controller methods that only accept value types and strings, but did not work for those that accepted classes.
It turns out there was an issue with the code for the updated MvcIntegrationTestFramework.
I figured out how to fix it, but don't know where else to post the solution, so here it is:
A simple sample to show how it works is:
[TestMethod]
public void Account_LogOn_Post_Succeeds()
{
string loginUrl = "/Account/LogOn";
appHost.Start(browsingSession =>
{
var formData = new RouteValueDictionary
{
{ "UserName", "myusername" },
{ "Password", "mypassword" },
{ "RememberMe", "true"},
{ "returnUrl", "/myreturnurl"},
};
RequestResult loginResult = browsingSession.Post(loginUrl, formData);
// Add your test assertions here.
});
}
The call to browsingSession.Post would ultimately cause the NameValueCollectionConversions.ConvertFromRouteValueDictionary(object anonymous) method to be called, and the code for that was:
public static class NameValueCollectionConversions
{
public static NameValueCollection ConvertFromObject(object anonymous)
{
var nvc = new NameValueCollection();
var dict = new RouteValueDictionary(anonymous); // ** Problem 1
foreach (var kvp in dict)
{
if (kvp.Value == null)
{
throw new NullReferenceException(kvp.Key);
}
if (kvp.Value.GetType().Name.Contains("Anonymous"))
{
var prefix = kvp.Key + ".";
foreach (var innerkvp in new RouteValueDictionary(kvp.Value))
{
nvc.Add(prefix + innerkvp.Key, innerkvp.Value.ToString());
}
}
else
{
nvc.Add(kvp.Key, kvp.Value.ToString()); // ** Problem2
}
}
return nvc;
}
Then there was two problems:
The call to new RouteValueDictionary(anonymous) would cause the "new" RouteValueDictionary to be created, but instead of 4 keys, there are only three, one of which was an array of 4 items.
When it hits this line: nvc.Add(kvp.Key, kvp.Value.ToString(), the kvp.Value is an array, and the ToString() gives:
"System.Collections.Generic.Dictionary'2+ValueCollection[System.String,System.Object]"
The fix (to my specific issue) was to change the code as follows:
var dict = anonymous as RouteValueDictionary; // creates it properly
if (null == dict)
{
dict = new RouteValueDictionary(anonymous);
}
After I made this change, then my model class would properly bind, and all would be well.

Resources