I am trying to pass a mocked domain instance called event to the controllers' show() method, but show() cannot find the Event in question and thus returns null.
Note that the following snippet is still work in progress.
def "trying to show an event containing malicous code"() {
given: "An event named with malicous code"
mockDomain(Event)
def event = Mock(Event)
event.title >> "<script type=\"text/javascript\">alert(\"XSS\");</script>"
event.id >> 1
// Do I have to actually create a full-blown event considering all
// constraints here?
when: "I try to show that event"
controller.params.id = 1
def result = controller.show()
then: "The resulting title will be encoded HTML"
result.eventInstance.title == event.title.encodeAsHTML()
}
This is the beginning of the controllers' show() method:
def show = {
def eventInstance = Event.get(params.id)
// The event exists
if (eventInstance) {
// some processing here
return [eventInstance: eventInstance, isSubscribed: sub ? true:false, sidebar: 'sidebar']
}
Is there a simple solution or will I have to actually create a full-blown event taking care of all constraints?
If I have to create a full event, where would I place the according method? (We're using a createEvent() method in BootStrap.groovy at the moment for initial setup, thus it wouldn't be DRY to repeat the function here).
Try mocking the Event object in the following way:
def event = new Event()
event.title = "<script type=\"text/javascript\">alert(\"XSS\");</script>"
event.id = 1 // optional
mockDomain Event, [event]
Unless you add an instance of event to the mockDomain call, you won't be able to retrieve it with get
Related
Will doing partialupdate() cause code in a data class' onUpdate Handler to run?
I have this setup in the data class:
exports.onUpdate = function(db, obj) {
DB.log.info(obj.ShiftID);
db.Shifts.load(obj.ShiftID)
.then((Shift) => {
DB.log.info(Shift);
if (Shift.User == db.User.me) {
Shift.User = null;
Shift.status = 0;
return Shift.update();
}
})
};
(yes, role 2 for node has permissions to query and update the Shifts data class)
But I am getting zero logs when I make a partialupdate(). Do I need to do a real update query...load the object, modify the data, update()?
Also it seems that this code causes the partialupdate() to not run at all, but when I delete the handler, it starts working again.
Yes, that is currently an unimplemented feature since a partial update can't execute an onUpdate handler since there is no object which can be passed to the update handler.
On the other hand, a partial update can't be executed directly since that will result in a security issue (since your onUpdate handler can contain validation code etc.)
So we currently reject any partial update on a class which has an onUpdate handler because there doesn't exist a way how we can actually validate the partial update against your onUpdate code.
We have planned that you can define an extra onPartial handler where you can take some extra steps before the partialUpdate is executed. But that handler will only get the partial update and not the object itself.
I'm pretty sure that partialupdate() will not cause the onUpdate Handler to run.
When I put the log line in and edit the records using website data manager it does log as expected. Not a big deal, I can just rewrite the query to be a full update.
BUT having any code in there does break partialupdate() which is not good.
Here is the code I'm using that works as long as there is nothing in the onUpdateHandler:
requestShift(shiftID) {
db.ready().then((db) => {
db.Applicants.find()
.where({
"shiftID": { "$in": [shiftID] },
})
.singleResult((applicants) => {
return applicants.partialUpdate()
.add("applicants", db.User.me.id)
.add("photos", this.props.UserData.photo)
.execute()
})
Alert.alert(
'Confirmation',
'Shift has been requested.',
)
this.props.navigation.dispatch(goToFindShifts)
})
}
I'm following the MVVM pattern, and have a model called a DocumentStore. The class has a method as follows:
void DocumentStore::Open_Document(StorageFile^ file) {
create_task(FileIO::ReadTextAsync(file))
.then([this, file](String^ fileContents)
{
// Take the fileContents and add them to internal data structure
});
}
My ViewModel is popping up a FileOpenPicker to get a file that it then feed as the argument into Open_Document:
create_task(picker->PickSingleFileAsync())
.then([this](StorageFile^ file)
{
m_DocStore->Open_Document(file);
// Target location to do something
}
);
I'd like to be able to perform an action after the task inside of Open_Document has completed, i.e. after the fileContents have been processed.
Is there a way for my Model to notify any interested listeners that a task is complete?
Or should my Model's Open_Document method actually be itself asynchronous? However, I need to process the data structure inside the task, and wouldn't that cause my method to be running inside a different thread context?
I'm working in C++/CX but will take any help I can get.
If I understand correctly, the process will be as following.
Open the file -> Read the content -> process the content -> do STH else.
You can push the async operation to the task chain and create a new async operation by using create_async method.
Here is the code for your reference:
create_task(StorageFile::GetFileFromApplicationUriAsync(ref new Windows::Foundation::Uri("ms-appx:///Assets/XMLFile.xml")))
.then([](StorageFile^ file) {
WriteLine("Read the file");
return FileIO::ReadTextAsync(file);
}).then([](task<String^> task) {
String ^ text = task.get();
WriteLine("Content: " + text);
return create_async([text]() {
WriteLine("Process the text: " + text);
});
}).then([](task<void> task) {
task.get();
WriteLine("Do STH else");
});
I'm posting what I ended up going with, but I accepted Jeffrey Chen's answer since it helped me get there.
My Model now has an Event DocOpened. This is fired upon completion of Open_Document. I subscribed my ViewModel to this Event with a handler that is capable of performing tasks whenever that Event is fired.
I never expected that I will need to ask a question on this site because everything is already answered normally but with Scalatra... I haven't find a lot of information so here it is:
I'm not experienced with all that so maybe I'm missing something but from what I understand, if I want to test the API that I develop on Scalatra, I need to start the server everytime I run the test suit, right ?
Second question, how can I reset the invocation counter on a method so I don't have to calculate how many times the method has been called since the beginning of the test suite ? Right now using this give me more than one because it counts the previous test.
there was one(*instance*).*method*(*parameter*)
I can still get around the problem by either counting or putting the test as first test for now but it's not a sustainable solution...
Other thing that I found:
Reset method on the mock... not found
http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#17
Isolating the test in a class scope:
We need to add
val servlet = new Servlet(eventRepoMock)
addServlet(servlet, "/*")
and we can't repeat the addServlet at every initialization
https://etorreborre.github.io/specs2/guide/SPECS2-3.5/org.specs2.guide.Isolation.html
Last thing that I try is:
servlet.repo = mock[EventRepo]
but repo being a value, I can't change it like this.
Neither of these "solutions" feel very clean so I was wondering if someone had a genius idea that can solve that mess !?
Thank you in advance !
EDIT:
Thanks to Eric's comment the above question are solve(that was easy) but now I have problem because I'm testing the get/post which are asynchronous call so resetting the mock does not happen at the right time... Any suggestion ?
Here's a simplified version of the code:
class EventServiceSpec extends ScalatraSpec with Mockito with Before { def is = s2"""
Event Service
GET an existing event
must return status 200 $get_status200
must return the event with id = :id $get_rightEventElement
must call findById once on the event repository $get_findByIdOnRepo
"""
lazy val anEvent = Event(1, "Some Event"
lazy val eventsBaseUrl = "/events"
lazy val existingEventUrl = s"$eventsBaseUrl/${anEvent.id}"
lazy val eventRepoMock = mock[EventRepository]
lazy val servlet = new Servlet(eventRepoMock)
addServlet(servlet, "/*")
def before = {
eventRepoMock.findById(anEvent.id) returns Option(anEvent)
eventRepoMock.findById(unexistingId) returns None
eventRepoMock.save(anEvent) returns Option(anEvent)
}
def get_status200 = get(existingEventUrl){
status must_== 200
}
def get_findByIdOnRepo = get(existingEventUrl){
// TODO count considering previous test... need to find a cleaner way
there was three(eventRepoMock).findById(anEvent.id)
}
All org.mockito.Mockito functions can still be used in a specs2 specification and reset is one of them.
Now, since you are sharing the state of a mock object across several examples, you not only need to reset the mock state before each example but you also need to make your specification sequential:
class EventServiceSpec extends ScalatraSpec with Mockito
with BeforeAll with BeforeEach {
def is = sequential ^ s2"""
Event Service
GET an existing event
must return status 200 $get_status200
must return the event with id = :id $get_rightEventElement
must call findById once on the event repository $get_findByIdOnRepo
"""
lazy val anEvent = Event(1, "Some Event")
lazy val eventsBaseUrl = "/events"
lazy val existingEventUrl = s"$eventsBaseUrl/${anEvent.id}"
lazy val eventRepoMock = mock[EventRepository]
lazy val servlet = new Servlet(eventRepoMock)
def beforeAll = addServlet(servlet, "/*")
def before = {
reset(eventRepoMock)
eventRepoMock.findById(anEvent.id) returns Option(anEvent)
eventRepoMock.findById(unexistingId) returns None
eventRepoMock.save(anEvent) returns Option(anEvent)
}
def get_status200 = get(existingEventUrl){
status must_== 200
}
def get_findByIdOnRepo = get(existingEventUrl){
there was one(eventRepoMock).findById(anEvent.id)
}
}
I am having a strange issue when mocking the log field of a class. Running the same test twice shows an error the second time. This is an example of code:
class AccountConfigJSON {
static Logger log = Logger.getLogger(AccountConfigJSON.class)
def AccountConfigJSON(String jsonString) {
if (jsonString) {
json = new JSONObject(jsonString)
} else {
log.debug("No JSON string for account config. Will not parse")
}
}
}
and this is the specification
class AccountConfigJSONUnitSpec extends UnitSpec {
def loggerMock
def setup(){
loggerMock = Mock(org.apache.log4j.Logger)
org.apache.log4j.Logger.metaClass.static.getLogger = { Class clazz -> loggerMock }
}
def 'If jsonString is null, a log is written'(){
when:
new AccountConfigJSON("")
then:
1 * loggerMock.debug("No JSON string for account config. Will not parse")
}
def 'If jsonString is empty, a log is written'(){
when:
new AccountConfigJSON("")
then:
1 * loggerMock.debug("No JSON string for account config. Will not parse")
}
}
The second test fails showing
| Too few invocations for:
1 * loggerMock.debug("No JSON string for account config. Will not parse") (0 invocations)
but debugging the app using Idea, clearly it runs this sentence. Any idea?
Looks odd that the actual call is executed but the interaction in not recorded. You can get around with it by explicitly assigning the mocked logger to the class as below:
def setup(){
loggerMock = Mock(org.apache.log4j.Logger)
AccountConfigJSON.log = loggerMock
}
From the definition of "interaction", I think the above setup is the best way to go.
Is an Interaction Just a Regular Method Invocation?
Not quite. While an interaction looks similar to a regular method
invocation, it is simply a way to express which method invocations are
expected to occur. A good way to think of an interaction is as a
regular expression that all incoming invocations on mock objects are
matched against. Depending on the circumstances, the interaction may
match zero, one, or multiple invocations.
This only happens while dealing with static object properties in a class. The moment logger is defined non-static in the class under test, everything works as expected without the work around.
Is there a way to pass parameters via the addTarget call as it calls another function?
I've also tried the sender method - but that seems to break as well. What's the correct way to pass the parameters without creating global variables?
#my_button = UIButton.buttonWithType(UIButtonTypeRoundedRect)
#my_button.frame = [[110,180],[100,37]]
#my_button.setTitle("Press Me", forState:UIControlStateNormal)
#my_button.setTitle("Impressive!", forState:UIControlStateHighlighted)
# events
newtext = "hello world"
#my_button.addTarget(self, action:'buttonIsPressed(newtext)', forControlEvents:UIControlEventTouchDown)
view.addSubview(#my_button)
def buttonIsPressed (passText)
message = "Button was pressed down - " + passText.to_s
NSLog(message)
end
Update:
OK, here's a method with an instance variable that worked.
#my_button = UIButton.buttonWithType(UIButtonTypeRoundedRect)
#my_button.frame = [[110,180],[100,37]]
#my_button.setTitle("Press Me", forState:UIControlStateNormal)
#my_button.setTitle("Impressive!", forState:UIControlStateHighlighted)
# events
#newtext = "hello world"
#my_button.addTarget(self, action:'buttonIsPressed', forControlEvents:UIControlEventTouchDown)
view.addSubview(#my_button)
def buttonIsPressed
message = "Button was pressed down - " + #newtext
NSLog(message)
end
The easiest way of attaching "parameters" to a rubymotion UIButton call is through the use of tags.
First set up a button with a tag attribute. This tag is the parameter you want to pass to the target function.
#button = UIButton.buttonWithType(UIButtonTypeRoundedRect)
#button.setTitle "MyButton", forState:UIControlStateNormal
#button.frame =[[0,0],[100,50]]
#button.tag = 1
#button.addTarget(self, action: "buttonClicked:", forControlEvents:UIControlEventTouchUpInside)
Now create a method that accepts sender as a parameter:
def buttonClicked(sender)
mytag = sender.tag
#Do Magical Stuff Here
end
Forewarning: As far as I know, the tag attribute only accepts integer values. You could get around this by putting your logic into the target function like this:
def buttonClicked(sender)
mytag = sender.tag
if mytag == 1
string = "Foo"
else
string = "Bar"
end
end
Initially I tried setting the action with action: :buttonClicked which worked but did not allow for using the sender method.
Yes, you usually create instance variables in your Controller class, and then just call methods on them from any method.
According to the documentation using setTitle is the general way to set a title of a UIButton instance. So you're doing it right.