How to Unit Test (mock class) in Groovy with nested closures? - unit-testing

I modified the code from here to look very much like the code I have and am trying to create Unit Tests for. While I would like to ask "what is the best way" to test this, I will be quite satisfied with any way to create a decent Unit Test! I looked at Spock, GroovyTestCase and GMock, while each of them may be quite capable of creating such a test I found the documentation for such an example lacking in all cases.
class Searcher {
def http = new HTTPBuilder('http://ajax.googleapis.com')
def _executeSearch = { searchQ -> {
req ->
uri.path = '/ajax/services/search/web'
uri.query = searchQ
requestContentType = URLENC
response.success = { resp, reader ->
assert resp.statusLine.statusCode == 200
reader.text
}
response.failure = { resp -> println "FAILURE! ${resp.properties}"
resp.statusLine.statusCode }
}
}
def executeSearch(query) {
// http.setHeaders(Accept: 'application/json') // I want JSON back, but this not important
http.request(GET, _executeGetCommand(query))
}
}
What I want/need to do is to mock 'http' in such a way that I can test:
1. uri.query is getting properly set via the passed in data
2. calls to response.success return mocked test data
3. calls to failure get executed and return the failure code
I am probably approaching this entirely incorrectly and will be open to the "right way" of going about unit testing such code. Please bear with me though as this is new to me!

I would use Spock mock's for your test case. They should be quite straightforward, since you don't need any actual network interaction during unit testing.
Spock mocks are documented pretty well in
the new spock docs
If you do want to test web services from the client side, check out geb, which works well as a companion to spock. Geb is documented in the Book of Geb Integration testing over the web obviously involves more moving parts, so you're right to start by mocking out the server side.

Related

Grails Unit Testing Issues

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
}
}

Testing afterInsert in Grails

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)

What test to write?

I know this is a basic question but due to lack of my knowledge I couldn't start writing test for my application. So here I am trying to learn and understand what to test and how to test based on my application scenario.
Class MyController {
MyService service = new MyService();
List<String> myList = service.generateSomeList(keyVal);
model.add("myList", myList);
}
Class MyService {
ThirdPatryService extService = new ThirdPatryService ();
MyDao dao = new MyDao();
public List<String> generateSomeList(Long key) {
List<String> resultList = dao.fetchMyList(key);
extService.processData(resultList); //using 3rd party service to process result. It doesn't return anything.
return formattedList(resultList);
}
private List<String> formattedList(List<String> listToProcess) {
//do some formatting
}
}
Class MyDao {
List<String> fetchMyList(key) {
//Use DB connection to run sql and return result
}
}
I want to do both unit testing and integration testing. So some of my questions are:
Do I have to do unit testing for MyDao? I don't think so since I can test query result by testing service level.
What can be the possible test cases for service level? I can think of test result from db and test formatting function. Any other test that I missed?
While testing generateSomeList() method is that OK to create dummy String list and test it against result? Like code below Am I creating list myself and testing myself. IS this proper/correct way to write test?
#Test
public void generateSomeListTest() {
//Step 1: Create dummy string list e.g. dummyList =["test1", "test2", "test3"]
//Step 2: when(mydao.fetchMyList(anyLong()).thenReturn(dummyList);
//Step 4: result=service.generateSomelist(123L);
//Step 5: assertEquals(result[i], dummyList[i]);
}
I don't think I have to test third party service but I think I have to make sure it is being called. Is this correct? If yes how can I do that with Mockito?
How to make sure thirdparty service has really done the processing of my data. Since its return type is void how can I do test it really done its job e.g like send email
Do I have to write test for controller or I can just write integration test.
I really appreciate if you could answer these question to understand the testing part for the application.
Thanks.
They're not really unit tests, but yes, you should test your DAOs. One of the main points in using DAOs is precisely that they're relatively easy to test (you store some test data in the database, then call a DAO method which executes a query, and check that the method returns what it should return), and that they make the service layer easy to test by mocking the DAOs. You should definitely not use the real DAOs when testing the services. Ue mock DAOs. That willmake the service tests much simpler, and much much faster.
Testing the results from DB is the job of the DAO test. The service test should use a mock DAO that returns hard-coded results, and checks that the service foes what it should do with these hard-coded results (formatting, in this case)
Yes, it's fine.
Usually, it's sufficient to stub the dependencies. Verifying that they have been called is often redundant. In that case, it could be a good idea since the third party service doesn't return anything. But that's a code smell. Why doesn't it return something? See the method verify() in Mockito. It's the very first point in the Mockito documentation: http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#1
The third party service is supposed to have been tested separately and thus be reliable. So you're supposed to assume that it does what its documentation says it does. The test for A which uses B is not supposed to test B. Only A. The test of B tests B.
A unit test is usually simpler to write and faster to execute. It's also easier to test corner cases with unit tests. Integration tests should be more coarse-grained.
Just a note: what your code severely lacks as is is dependency injection. That's what will make your code testable. It's very hard to test as is because the controller creates its service, which creates its DAO. Instead, the controller should be injected with the service, and the service should be injected with the DAO. That's what allows injecting a mock DAO in the service to test the service in isolation, and to inject a mock service into the controller to test the controller in isolation.

How do I write test(s) for this in Symfony?

I'm about to delve into test in the PHP world and I have some questions. I have a controller which handles a loan application. The bulk of the work is then delegated to a ProcessLoanApplication class.
ApplyController
class ApplyController extends Controller
{
public function indexAction(Request $request)
{
$form = $this->createForm(new LoanApplication());
if($request->getMethod() == 'POST') {
$form->bind($request);
if($form->isValid()) {
$session = $this->getRequest()->getSession();
$loan_app_processor = new Tasks\ProcessLoanApplication($form, $session);
$loan_app_processor->process();
return $this->redirect($this->generateUrl('apply_thanks'));
}
}
Tasks\ProcessLoanApplication
class ProcessLoanApplication
{
private $_QuickBaseModels;
private $_session;
private $_app; // submitted form data
private $_existingApp = false; // holds existing application in QB, if it exists
public function __construct(Form $form, Session $session)
{
$this->_app = $form->getNormData();
$this->_session = $session;
// save the form data to a session
$session->set('application', $this->_app);
// create the quickbase table models objects
$this->_QuickBaseModels['GenFnHome\Application'] = new GenFnHome\Application();
$this->_QuickBaseModels['GenFnHome\SSN'] = new GenFnHome\SSN();
}
public function process()
{
$this->_existingApp = $this->_getExistingApplication();
$app_status = $this->_existingApp[GenFnHome\SSN::LogInApplicationStatus];
if(!$this->_existingApp || ($this->_existingApp && ($app_status !== 'PENDING' && $app_status !== 'OPEN' && $app_status !== 'EXPIRED')))
return $this->_saveNewLoanApplication();
if($app_status == 'EXPIRED') $this->_reOpenApplication();
}
There's a lot going on here, so I will outline it first:
User makes a requests for the application
Application form is validated
If valid, process loan application
Check if the user already has an app, if so - do X, if not Y
The application is persisted in an 'online database' (QuickBase) that my application communicates with via XML over HTTP (in other words, there is no real db)
My questions to the community:
What should be tested here? I know it is largely up to me, but perhaps the community can recommend some baseline tests that should def be written. Should I be testing the controller, the processor class, and the QuickBase class?
Should my tests be independent of one another - meaning, I should test each component individually, rather than have one massive testApplication that does everything the indexAction does and just looks for the expected sessions vars that get set?
Finally, how does one test API calls (request / response) without actually making real request (I'm using PHPUnit).
Anything else I should know?
Thanks!
What should be tested here? I know it is largely up to me, but perhaps the community can recommend some baseline tests that should def be written. Should I be testing the controller, the processor class, and the QuickBase class?
I recommend to test every class you build. If you are using Test Driven Development, the test declares what you are building, no test no code.
Should my tests be independent of one another - meaning, I should test each component individually, rather than have one massive testApplication that does everything the indexAction does and just looks for the expected sessions vars that get set?
Every Unit test should be isolated and should only test the Class that you are testing. You should use Mock object (use the PHPunit mock library or other 3th party libraries as Mockery) if one object dependences on another object.
Finally, how does one test API calls (request / response) without actually making real request (I'm using PHPUnit).
You can use the Symfony's WebTestCase that provides easy methods to imitate a browser request, learn more about that in the documentation. We call that Functional Testing.
This is usually the stage after Unit Testing. In Unit Testing you will test each individual class (it's a good practice to unit test your controller) and after that you write your Functional Tests which combines everything and tests if it works like expected.
for Controllers you should use functional tests (http://symfony.com/doc/2.0/book/testing.html#functional-tests). With them you can emulate browser and user's actions like submiting form and checking validation, database changes, http status codes and so on.
You should not forget to unit test ProcessLoanApplication.
I dont realy know why you pass form object to ProcessLoanApplication anyway. You should pass entity - it has normdata already.

Which Scala framework to use for testing REST services?

I'd like to use Spec2 and Scala to test a REST service that was build using Java. I looked at Spray but it seams like you have to build your application using Spray in order to test it using SprayTest. I also found this thread but it's not really what I'm looking for.
Any other ideas?
We have successfully been testing all of our REST APIs using Specs2 and the Dispatch library (https://dispatchhttp.org/Dispatch.html). Dispatch takes a little bit of time to get your head around, but once you understand how it composes everything together with various operators you can test a simple REST service with a couple of lines of code.
Here's a couple of test cases from out recent project:
def issueErrorStatus = {
val requestBody = "msisdn=447777666666&message=Some test message"
val req = url("http://localhost:%d/otac/issue".format(port)) <<
(requestBody, "application/x-www-form-urlencoded")
val response = Http.when(_ == 400)(req <:< (touchPointHeaders) as_str)
response must_== """{"error":"Message must contain an {OTAC} place holder"}"""
}
def checkOtac = {
val req = url("http://localhost:%d/otac/check".format(port)) <<?
Vector(("msisdn" -> "447777123456"))
val response = Http(req <:< (touchPointHeaders) as_str)
response must_== """{"status":"Present","reissueAllowed":true}"""
}
The first test makes a post request, the second a get request. We also have some more complex tests that parse the response JSON string through the lift-json parser so that we can assert agains the document more easily. The above tests are just checking some simple error/status cases.
There's also a dispatch-reboot project underway that has a simplified API and works with async connections. Not sure how stable it is yet though.
In my last projects I used AsyncHttpClient and Jersey Client for testing REST services and I can recommend both of them. For async operations the former is better (I don't know if jersey client
supports async operations at all).
They are written in Java and have (to my knowledge) no Scala-API.