Was writing unit test cases and at one point I needed to do some meta programming to test a method as below.
void "test method:resolver"(){
setup:"mocked resolver"
ContextHolder.getMetaClass().static.getBean = {
Resolver resolver = Mock(Resolver)
resolver(_) >> {HttpServletRequest request1->
return 1;
}
}
and:"mocked getAppName"
CoreUtil.metaClass.static.getAppName = {
return "$apiName"
}
when:
UserGroupRole userGroupRole = service.resolve(username)
then:
userGroupRole != null
where:
apiName || username
"core-blog" || "test11"
}
Following are the scenarios that I have gone through for running test cases:
When running test case individually, It works perfectly.
When running test case as a whole Specification i.e. run the Specification class itself, It works perfectly
But when running the test cases as whole by
grails test-app :unit
It fails saying Class.metaclass.static say can not get static on null
Please help!
If you're making metaclass changes in your tests, you need to clean up those metaclass changes in a cleanup step at the end of each test. Otherwise you risk test pollution.
setup
metaclass work
when
then
cleanup:
revoke the metaclass changes here
where
Usually I was ending up writing test cases for a Domain by writing them for constraints and any custom methods(created by us in application) as we know we shouldn't test obvious.
But the time we started using coverage plugin, we found that our domains line of code is not fully covered which was due to gorm hooks(onInsert, beforeUpdate) that we never wrote test cases for.
Is there a way we can test these. One possible way that seems obvious but not suitable is to call another method(containing all code which was earlier in hooks) within these hooks and test that method only and be carefree for hooks.
Any solutions...
Edit
Sample code in domain that I want to unit-test:
class TestDomain{
String activationDate
def beforeInsert() {
this.activationDate = (this.activationDate) ?: new Date()//first login date would come here though
encodePassword()
}
}
How can I unit-test beforeInsert or I would end up writing integration test case?
Perhaps a unit test like:
import grails.test.mixin.TestFor
#TestFor(TestDomain)
class TestDomainSpec extends Specification {
def "test beforeSave"() {
given:
mockForConstraintsTests(TestDomain)
when:
def testDomain = new TestDomain().save(flush:true)
then:
testDomain.activationDate != null
}
}
I have the following two Spock tests:
def "sends a valid response when no users exist"() {
setup:
def exchange = new HttpServerExchange(Mock(ServerConnection))
usersRepository.size() >> 0
when:
firstRunHandler.handleRequest(exchange)
then:
1*response.send(exchange, _)
}
def "does not send content when any users exist"() {
setup:
usersRepository.size() >> 1
when:
firstRunHandler.handleRequest(new HttpServerExchange(Mock(ServerConnection)))
then:
0*response.send(_, _)
}
The second one should definitely fail, since the interaction is stll there. But it always passes. I can not even make it fail with:
then:
assert false
0*response.send(_, _)
IntelliJ Idea still shows it as "green". But when I change the "then" to
then:
assert false
the test fails, so it is definitely being run and executed as a spock test.
I don't get much info from Spock, and I did not find out anything when debugging. What am I missing? What can I do to diagnose this problem?
I'm using BOOST TEST and I wonder if there is a way to find out the test suite from inside the test case. I know that I can find test case's name by:
boost::unit_test::framework::current_test_case().p_name
Is there a way to find out the suite name also?
My suites-cases structure is:
suite ---> case 1
______|--> case 2
______|--> case 3
Thanks
A unit_test has not only p_name but also p_parent_id, which is the ID of the test suite. Both those properties are inherited from test_unit, which is the common base class for unit_test and test_suite.
To get the suite from the ID, we can look at how current_test_case works:
test_case const&
current_test_case()
{
return get<test_case>( s_frk_impl().m_curr_test_case );
}
The m_curr_test_case member is a test_unit_id, just like p_parent_id. So, to get the test suite of the current test case, you can use this:
framework::get<test_suite>(current_test_case().p_parent_id)
Finally, test_suite has a p_name property just like unit_test, so you should find the name there.
I've written a lot of django applications and become accustomed to extending unittest.TestCase and running python manage.py test app_name. Is there a similarly simple way to unit test Kanso apps? Please provide a minimal example.
Thanks.
Kanso apps are CouchDB apps. However the best bang-for-buck is to ignore CouchDB for now. The important thing is this: Kanso apps are Node.js apps. Test them the same way you would test a Node.js app. Test that they adhere to the documented CouchDB API and you will be fine.
Ideally, we might want to run tests actually in CouchDB. The JavaScript engines are different (V8 vs. SpiderMonkey); the environments are different. However in practice, it is so much easier to test Node.js code. (Also, a whole class of JavaScript bugs are absent on both platforms: third-party code setting global variables, changing built-in types, changing prototypes—those are all browser issues. Node.js and CouchDB are both pristine and predictable.)
Example
Let's make a simple Couch app that outputs "Hello world" in a _show function.
The kanso.json file:
{ "name" : "hello_world"
, "version": "0.1.0"
, "description": "A simple hello-world Couch app"
, "dependencies": { "node-couchapp": "~0.8.3" }
, "app": "app"
}
Next run kanso install which will pull in the "node-couchapp" dependency. (Notice how using the kanso command is similar to using the npm command.)
Let's make a very simple Couch app, in ./app.js:
// A Couch app that just says hello in a _show function.
module.exports = {
'shows': {
'hello': function(doc, req) {
var who = req.query.who || "world"
return "Hello, " + who
}
}
}
I ran kanso push http://example.iriscouch.com/so_hello and I can see my app here:
http://example.iriscouch.com/so_hello/_design/hello_world/_show/hello
http://example.iriscouch.com/so_hello/_design/hello_world/_show/hello?who=Stack+Overflow
Adding Tests
I like node-tap so let's use that. But the main point is, this is just some Node.js code. Test it using whatever method your prefer.
First, a quick package.json file:
{ "name" : "hello_world"
, "description": "A simple hello-world Couch app"
, "version": "0.1.0"
, "private": true
, "devDependencies": { "tap": "~0.2.3" }
}
Run npm install to get the node-tap package. (And I always have ./node_modules/.bin in my $PATH when I work on Node.js. Rather than a global install, I like to have everything I need right there in the project.
Next, perhaps a test/show_function.js file:
var tap = require('tap')
tap.test('The Couch app loads', function(t) {
t.doesNotThrow(load_app, 'No problem loading the app.js file')
t.end()
function load_app() {
var app = require('../app')
}
})
tap.test('The show function', function(t) {
var app = require('../app')
, hello = app.shows.hello
t.type(hello, 'function', 'Show function "hello" in the couch app')
var doc = {}
, null_req = {'query':{}}
, john_req = {'query':{'who':'John Doe'}}
t.equal(hello(doc, null_req), 'Hello, world', '"Hello world" by default')
t.equal(hello(doc, john_req), 'Hello, John Doe', 'Supports ?who query string')
t.end()
})
Test it by running tap test:
$ tap test
ok test/show_function.js ................................ 5/5
total ................................................... 5/5
ok
I'll change the code to return "Hello, world" hard-coded (i.e., ignore the req.query.who parameter). Notice the failing test:
$ tap test
not ok test/show_function.js ............................ 4/5
Command: "node" "show_function.js"
ok 1 No problem loading the app.js file
ok 2 Show function "hello" in the couch app
ok 3 "Hello world" by default
not ok 4 Supports ?who query string
---
file: /private/tmp/j/test/show_function.js
line: 23
column: 5
stack:
- getCaller (/private/tmp/j/node_modules/tap/lib/tap-assert.js:403:17)
- assert (/private/tmp/j/node_modules/tap/lib/tap-assert.js:19:16)
- Function.equal (/private/tmp/j/node_modules/tap/lib/tap-assert.js:160:10)
- Test._testAssert [as equal] (/private/tmp/j/node_modules/tap/lib/tap-test.js:86:16)
- Test.<anonymous> (/private/tmp/j/test/show_function.js:23:5)
- Test.<anonymous> (native)
- Test.<anonymous> (events.js:88:20)
- Test.emit (/private/tmp/j/node_modules/tap/lib/tap-test.js:103:8)
- GlobalHarness.<anonymous> (/private/tmp/j/node_modules/tap/lib/tap-harness.js:86:13)
- Array.0 (native)
found: Hello, world
wanted: Hello, John Doe
diff: |
FOUND: Hello, world
WANTED: Hello, John Doe
^ (at position = 7)
...
ok 5 test/show_function.js
1..5
# tests 5
# pass 4
# fail 1
total ................................................... 4/5
not ok
I have some projects that may help showcase testing kanso apps:
Dashboard Core Project
https://github.com/ryanramage/dashboard-core
Features:
Travis Support.
PhantomJS headless testing using NodeUnit
Since this is a module, we have a test folder, that is a seperate kanso app that uses the module. Note in the packages folder there is a symlink back to the root of the project.
Node-Couchapp Project
https://github.com/kanso/node-couchapp
Travis support
This time multiple test kanso projects in the kanso folder. Again using the symlink trick in the package directory
Like JasonSmith, I also recommend you test using Node.js where possible. However, due to the nature of CouchApps you often end up having to write unit tests to run in the browser, either because they interact with browser APIs you don't want to mock or because you need to test it works in a range of browsers.
When doing browser-based unit tests I use a few little Kanso packages I hacked together to automatically present an interface for running nodeunit test suites. It's a bit rough around the edges at the moment but gets the job done.
kanso.json
Add nodeunit and nodeunit-testrunner packages to your kanso.json file and run kanso install to fetch them from the repositories.
{
"name": "example",
"version": "0.0.1",
"description": "example app with unit tests",
"modules": ["lib", "tests"],
"load": "lib/app",
"dependencies": {
"modules": null,
"properties": null,
"nodeunit": null,
"nodeunit-testrunner": null
}
}
Notice that I've included the 'tests' directory as a module path. Any modules dropped into that directory will be used as nodeunit test suites and displayed by the nodeunit-testrunner UI.
Rewrites
You need to manually add the nodeunit-testrunner package's rewrites to your app, in my example that means editing lib/app.js to look like the following:
exports.rewrites = [
require('nodeunit-testrunner/rewrites')
];
Add some tests
Assuming we have a module lib/foo.js that looks like this:
exports.hello = function (name) {
return 'hello ' + name;
};
We could add a test by adding a module at tests/test-foo.js (this can be named anything so long as it's inside the tests directory).
var foo = require('lib/foo');
exports['test for foo.hello'] = function (test) {
test.equal(foo.hello('bar'), 'hello bar');
test.done();
};
If you then push your app and visit http://localhost:5984/example/_design/example/_rewrite/test in the browser you will be presented with a basic interface for running the test suites in the tests directory, either individually or all of them one after another.
Hope that helps.