Understanding legacy grails code? - unit-testing

The following is a chunk of code in setUp method of controller unit test class in grails. I am trying to understand the purpose of the following setup code. The application has a TimeService which is responsible for doing time operations. I appreciate any help!
def customPropertyEditor = new CustomPropertyEditorRegistrar(timeService: new TimeService())
def map = (Map<String, PropertyEditorRegistrar>) servletContext.getAttribute(GrailsDataBinder.PROPERTY_EDITOR_REGISTRARS)
if (!map) servletContext.setAttribute(GrailsDataBinder.PROPERTY_EDITOR_REGISTRARS, [customPropertyEditor: customPropertyEditor])
else map.put('customPropertyEditor', customPropertyEditor)

Create this TimeService object that is customPropertyEditor
def customPropertyEditor = new CustomPropertyEditorRegistrar(timeService: new TimeService())
Make a map out of servletContext.getAttribute(GrailsDataBinder.PROPERTY_EDITOR_REGISTRARS
def map = (Map<String, PropertyEditorRegistrar>) servletContext.getAttribute(GrailsDataBinder.PROPERTY_EDITOR_REGISTRARS)
if (!map) = If no map found = as in null due to no results
Then set servletContext.setAttribute(GrailsDataBinder.PROPERTY_EDITOR_REGISTRARS to be the object at the top customPropertyEditor
servletContext.setAttribute(GrailsDataBinder.PROPERTY_EDITOR_REGISTRARS, [customPropertyEditor: customPropertyEditor])
If there was a map put in the map customPropertyEditor this value
else map.put('customPropertyEditor', customPropertyEditor)
As for what GrailsDataBinder is doing as Servlet Attribute have a search for it in the code base to see what other things are interacting

ok i found that this chunk of code is responsible for making it so that date binds well. Apparently, there is no clean method to bind date in grails 2.2.

Related

APEX: Assigning a Map without a Key to a List

Sorry for the newbie question. Learning Apex here. Been working on an issue for several hours and can't seem to needle it out.
I have a JSON that I need converted to a List... the JSON is retrieved via an API. The code is pretty simple, it is only a couple of lines.
The JSON looks like this:
{"id":1,"abbreviation":"ATL","city":"Atlanta","conference":"East","division":"Southeast","full_name":"Atlanta Hawks","name":"Hawks"}
And the code I am told to use to retrieve it looks like this:
Map<String, Object> resultsMap = (Map<String, Object>) JSON.deserializeUntyped(results.getBody());
Based on the JSON provided, there does not appear to be a MAP key being assigned, so I have no idea how to get it so that I may assign it to a List...
I've already tried assigning it directly to a List, but I didn't get much success there either.
I've tried this already:
List<Object> other = (List<Object>) results.get('');
I've also tried this:
List<Object> other = (List<Object>) results.keySet()[0];
I'm sure it is something simple. Any help would be appreciated.
Thanks
You cant convert the map to a list without an id. Alternatively why to convert it to List. Use the map itself. Below is a code example of how you can use it using your JSON response. For example, I want to insert this JSON response into the contact record, so I can map it using the MAP itself.:
#RestResource(urlMapping='/URIId/*')
global class OwneriCRM {
#HttpPut
global static String UpdateOwnerinfo(){
RestRequest req= RestContext.request;
RestResponse res= RestContext.response;
res.addHeader('Content-type','application/JSON');
Map<String,Object> responseresult=new Map<String,Object>();
Map<String,Object> results= (Map<String,Object>)JSON.deserializeUntyped(req.requestBody.toString());
List<contact> insertList = new List<contact>();
for (String key : results.keySet()){
System.debug(results.get(key));
contact c= new contact();
c.ContactField__C = results.get(id);
c.ContactField1__C = results.get(city);
c.ContactField2__C = results.get(conference);
c.ContactField3__C = results.get(division);
c.ContactField3__C = results.get(full_name);
c.ContactField3__C = results.get(name);
insertList.add(c);
}
if(!insertList.Isempty()){
update insertList;
}
Question can be disregarded. Not sure if there is a way to withdraw the question.
Question was based on the fact that previous APIs had been sent in the following format:
{"data": {"more stuff": "stuff"} }
And the map key was 'data' with a list. In this scenario, the whole API was a list and the keys to the map were set in place with the actual values instead.

How do I mock local variables of a mocked class in a Spock test?

Let's say I have the following method in a service:
private void deleteItems(List<Item> itemsToDelete) {
def sql = new Sql(dataSource)
itemsToDelete?.each { Item item ->
sql.execute("DELETE FROM owner_item WHERE item_id = ${item.id}")
item.delete(flush: true, failOnError: true)
flushDatabaseSession();
}
}
How do I create a test for this method in the ItemServiceSpec? When I try it, I get either a DataSource "Must specify a non-null Connection" error or a nullPointerException on sql.
This is my existing test.
#TestFor(ItemService)
#Mock([Item])
#Build([Item])
class SubjectServiceSpec extends Specification {
...
def "delete items"() {
given:
Item item1 = Item.build().save(flush: true)
Item item2 = Item.build().save(flush: true)
Item.count() == 2
DataSource mockDataSource = Mock()
service.dataSource = mockDataSource
1 * deleteItems
when:
service.deleteItems([item1, item2])
then:
Item.count() == 0
}
}
What you are trying to do here, is to mock a dependency (DataSource) of a dependency (Sql). This normally leads to a situation, where you a not 100% aware of how the Sql interacts with the DataSource Object. If Sql changes private interaction with the Datasource in a Version Update, you have to deal with the situation.
Instead of mocking a dependency of a dependency you should the Sql Class directly. For this, the sql has to be some kind of explicit dependency that you can receive via DI or a method parameter. In this case you can just mock the execute call like so (choosen the way of a Expando-Mock, but you could also use Map or the Mock Stuff from Spock):
given:
def sqlMock = new Expando()
sqlMock.execute = { return 'what ever you want or nothing, because you mock a delete operation' }
service.sql = sqlMock
when:
service.deleteItems([item1, item2])
then:
assertItemsAreDeletedAndTheOwnerAsWell()
Thinking about the whole testcase, there a two major problems in my opinion.
The first one is, when you ask yourself what kind of certainty do you really get here by mocking out the whole sql stuff. In this case, the only thing that you are doing here is to interact with the db. When you mock this thing out, then there is nothing anymore that you could test. There is not many conditional stuff or anything that should be backed up by a unit test. Due to this, I would suggest to write only integration spec for this test-case where you have something like a H2DB for testing purposes inplace.
The second thing is, that you actually don't need the Sql Manipulation at all. You can configure GORM and Hibernate in a way do a automatic and transparent deletion of the owner of the item, if the item is deleted. For this, look at the docs (especially the cascade part) from GORM or directly in the Hibernate docs.
To sum it up: use cascade: 'delete' together with a proper integration test and you have a high amount of certainty and less boilerplate code.

Issue overriding method using mockFor and MockDomain

I'm trying to unit test a service and I would like to use a mock to override a method on domain object which retrieves a file from a DB.
def mockElem = mockFor(DataElement, false)
mockElem.demand.getFile(){return tempFile}
def dataElem = mockElem.createMock()
dataElem.orderId = "123"
dataElem.id = tempFileName
dataElem.dataType = "cnv"
dataElem.dataStatus = DataStatus.TRANSFERED
mockDomain(DataElement, [dataElem])
When I call a dynamic finder on the data element I want this Mock Domain to be returned with the mockFor demand functionality for getFile. An Assertion error is thrown when the MockDomain line is reached
junit.framework.AssertionFailedError: No call to 'getClass' expected
at this point. Still 1 call(s) to 'getFile' expected. at
groovy.mock.interceptor.StrictExpectation.match(StrictExpectation.groovy:56)
at grails.test.GrailsMock.createMock_closure1(GrailsMock.groovy:136)
at
grails.test.MockUtils.updateMetaClassForClass_closure95(MockUtils.groovy:1297)
at groovy.lang.Closure.call(Closure.java:412) at
groovy.lang.Closure.call(Closure.java:425) at
grails.test.MockUtils.updateMetaClassForClass(MockUtils.groovy:1294)
at grails.test.MockUtils.mockDomain(MockUtils.groovy:470) at
grails.plugin.spock.UnitSpec.mockDomain(UnitSpec.groovy:141) at
com.genospace.inbound.pg.HemeCNVPipelineTestSpec.test processing Heme
file(HemeCNVPipelineTestSpec.groovy:66)
Not sure what is the question.
You got this error because you are mocking an object twice :
with mockFor/createMock
with mockDomain
mockDomain need to know some information about objects being passedas arguments (here it verifies the class is correct) but mockFor did not allow that getClass() was called : you did not add a demand for such call.
Do you really need to mock with demand ?
I think the simple case should work :
def dataElem = new DataElement()
dataElem.orderId = "123"
dataElem.id = tempFileName
dataElem.dataType = "cnv"
dataElem.dataStatus = DataStatus.TRANSFERED
dataElem.file = tempFile
mockDomain(DataElement, [dataElem])

Pyamf register_class not mapping strongly typed objects as expected

I'm using Pyamf as my backend for my Flex app and I'm seeing some weird problems with the mapping of the stongly typed classes.
Here is the model that I'm returning
class MilestonActBase(RewardActBase):
def __unicode__(self):
return self.milestone.title
class Meta:
abstract = True
class SouvenirAct(MilestonActBase):
souvenir = models.ForeignKey(Souvenir)
group = models.ForeignKey(Group, blank=True, null=True)
def __unicode__(self):
return self.souvenir.title
Here is my method that returns the objects in my views.py:
try:
pyamf.register_class(Souvenir, 'com.rain.dennys.services.vo.Souvenir')
pyamf.register_class(SouvenirAct, 'com.rain.dennys.services.vo.SouvenirAct')
except ValueError:
print "Classes already registered"
#login_required
def get_souvenir_acts(http_request):
user = http_request.user
souvenirActs = SouvenirAct.objects.filter(user=user)
return souvenirActs
Here is my AS3 class:
package com.rain.dennys.model
{
[RemoteClass (alias="com.rain.dennys.services.vo.SouvenirAct")]
[Bindable]
public class SouvenirAct extends RewardActBase
{
public var souvenir:Souvenir;
public function SouvenirAct()
{
}
}
}
When I call the service, I get back and array of anonymous objects, even though I've done the register_class in python and RemoteClass in Flex. So that doesn't make sense to me. I must be doing something wrong?
In playing around with it, I've tried a few different things. One thing that kinda worked was to iterate on the array in Flex and cast the items as SouvenirAct objects like so:
private function onResult(r:Array):void
{
for each(var o:Object in r)
{
var c:SouvenirAct = o as SouvenirAct;
}
}
When I do that in Flex, I get my SouvenirAct objects are typed as they should be, BUT then the child souvenir objects are all null. So when I force the casting of the SouvenirAct objects in the return result, I get null for the child properties that are strongly typed.
Has anyone see this before? Is there a different way I should be mapping classes?
So I'm now pretty certain the problem was with the netConnection class. I switched it out so I could use RemoteObject, and now everything works exactly as expected.
This is how I was connecting:
netConnection.connect("http://127.0.0.1:8000/gateway/");
netConnection.addEventListener(NetStatusEvent.NET_STATUS, onError);
var responder:Responder = new Responder(onResult, handleFault);
Then I switched to what is described here: http://www.adobe.com/devnet/flex/articles/flex_django.html If anyone else runs into this, and you are using netConnection, my advice is to go with RemoteObject
Okay, so this is kind of a guess but this has stung me a few times. Have you ever instantiated an instance of Souvenir anywhere in your flex application? If not... AS did not bother to compile it and you'll get anonymous objects back.
When you do your onResult looping block of code, it works because you're instantiating an object of SouvenirAct, but never instantiating a Souvenir (child), so it's still null because ActionScript never compiled it...Try this before your service call
//TODO: remove me later
var imjustheretocompile:Souvenir = new Souvenir();
var alsoCompileMetoo:SouvenirAct = new SouvenirAct();
Now since you've created an instance of SouvenirAct, it should actually be compiled into your app. This is usually never a problem since we presume you will be using that class at some point, then you can go back and remove the imjustheretocompile and alsoCompileMetoo variables.

Mock a method for Grails Unit Test

In one of my unit tests, I am having some difficulty getting a mocked method to executed. I have the following test code:
void testExample() {
def mockICFService = new MockFor(ICFService)
...
//Mock the methods
controller.metaClass.icfList = { def person ->
println "icfList"
return [new IC(conceptId:'12345')]
}
mockICFService.demand.getAllIC(1..1) { def id, def withHist, def appId ->
println "mocking service"
return new Person()
}
...
def model = controller.detail()
}
Inside of detail in my controller class I create a Person via the ICFService's getAllIC(). This part works correctly. Later in the function, however, there is a call to icfList (which is defined in the controller). Through println's I have determined that the call is still being made, although it is returning an empty array. I believe that this is because the array is populated based on data in the servletContext, but in Unit Testing there is no access to that (hence my trying to mock it out).
Does anyone know how to force the test to use the mocked version of controller.icfList instead of calling the actual method in controller?
When I try your code, what blows up for me is the mocked service, and the part that works properly is the mocked-out icfList() method. The opposite of your observation, interestingly. For what it's worth, here's what I did:
First replace new MockFor() class instantiation with the mockFor() method. Then you need to inject the mock service into the controller.
def mockICFService = mockFor(ICFService)
controller.iCFService = mockICFService.createMock()
By doing the above, only the mocked versions of icfList() and getAllIC() get called, so you are not using the servletContext at all. Check out the Grails testing documentation for more info.