Testing HTTP using Kiwi/Nocilla - web-services

I just started developing an app that connects to this URL and retrieves the rate exchange for a given pair of currencies.
I need to test the HTTP request and I ended up learning about Kiwi and Nocilla. However, I'm completely new to any kind of testing and there's not a lot of information about Nocilla that can help me to get started.
I added all the NSURLConnectionDataDelegate and NSURLConnectionDelegate methods to the ViewController of my single view application, and the data retrieved from the URL is stored in #property (strong, nonatomic) NSMutableData *receivedData;. When I run the program everything works as expected but I haven't been able to pass the test I wrote:
SPEC_BEGIN(URLConnectionSpec)
__block URLConnectionAppDelegate *app_delegate;
__block URLConnectionViewController *view_controller;
describe(#"URLConnection", ^{
beforeAll(^{
[[LSNocilla sharedInstance] start];
app_delegate = [[UIApplication sharedApplication] delegate];
[[app_delegate shouldNot] beNil];
view_controller = app_delegate.viewController;
});
afterAll(^{
[[LSNocilla sharedInstance] stop];
});
afterEach(^{
[[LSNocilla sharedInstance] clearStubs];
});
context(#"When testing", ^{
it(#"should do something", ^{
stubRequest(#"GET", #"http://rate-exchange.appspot.com/currency?from=USD&to=EUR&q=1");
[view_controller beginCommunication];
[[expectFutureValue([NSString stringWithUTF8String:[view_controller.receivedData bytes]]) shouldEventuallyBeforeTimingOutAfter(2)] equal:#"{\"to\": \"EUR\", \"rate\": 0.76610740799999999, \"from\": \"USD\", \"v\": 0.76610740799999999}"];
});
});
});
SPEC_END
I'm sorry for the long snippet of code.
The test always failed with this message
URLConnection_WhenTesting_ShouldDoSomething] : 'URLConnection, When testing, should do something' [FAILED], expected subject to equal "{"to": "EUR", "rate": 0.76610740799999999, "from": "USD", "v": 0.76610740799999999}", got ""
I tried changing the time to even 10 seconds hoping that the test finished too early but I got the same results. I don't know why 'receivedData' is empty.
I would really appreciate any help

See discussion in comments: the overall structure of the Kiwi test looks good, the Nocilla stubRequest function call doesn't seem to result in the response that the test is expecting.
Perhaps you could use andReturnRawResponse to set up the expected response data. Something like this (assuming I got the Nocilla syntax correct):
NSData *rawData = ...
stubRequest(...).andReturnRawResponse(rawData);
[view_controller beginCommunication];
[expectFutureValue([view_controller.receivedData bytes])
shouldEventuallyBeforeTimingOutAfter(2)] equal:rawData.bytes];

Related

'Content-Length: 0', Javascript, XMLHttpRequest, Django REST API

I wish I can find some assistance with my code.
I have set up a Database on mySQL, and connected it to Django REST. Those both work as expected, and I can access the REST with Firefox REST Client with it returning the correct tables from the database.
I have started working for user interface with html and javascript and I have encountered a problem I am unable to solve. I am a student, and this is part of my school work, but unfortunately my teachers are unavailable at the moment due summer vacations and I am eager to continue my project. Hence I am askin for Your assistance.
As I have tested the Django REST through Firefox REST Client, I am sure the database and REST service is not at fault so here we come to my code.
I seem to be able to get connection to the REST Service, giving me code 200 and state 4 (pictures linked underneath)
ReadyStateChange + ReadyState console.logs
Picture 2 shows that my GET request gets stuck on OPTIONS, instead of executing the correct request.
200 OPTIONS
However I am unable to pull data out, giving me 'Content-Length: 0'.
Originally I thought the issue would be cross-domain request problem until my fellow student said he does not think it is, however he was unable to find solution for my code either.
I am trying to find reason and workaround for this error, and if you guys do have idea why this is happening I would deeply appriciate your help!
Here is my code:
<div id="demo"></div>
<script>
loadData() //function kutsu
function loadData(){
if (window.XMLHttpRequest) {
// code for modern browsers
xmlhttp = new XMLHttpRequest();
} else {
// code for old IE browsers
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
var url = "http://127.0.0.1:8000/vamkrs/";
xmlhttp.open("GET", url, true);
xmlhttp.withCredentials = true;
xmlhttp.setRequestHeader("Authorization", "Basic " + btoa("username:password"));
xmlhttp.send();
setTimeout(xmlhttp.onreadystatechange = function() {
console.log(this.status);
console.log(this.readyState);
if (this.readyState == 4 && this.status == 200) {
var myData = JSON.parse(this.responseText);
document.getElementById("demo").innerHTML = myData.responseText(); }
},1500);
/*
xmlhttp.onreadystatechange = function(){
console.log(this.status);
if (this.readyState == 4 && this.status == 200) {
var myData = JSON.parse(this.responseText);
document.getElementById("demo").innerHTML = myData.responseText();}
}; */
}
</script>
Ps. Sorry, English is not my native language so some spelling mistakes might have been made
Pss. First time posting here, I apologize if mistakes were made on the post

API integration testing - is it bad practice to test Post/Put/Delete in a single test method?

I have been mulling on ways to end-to-end test an API call, with the likes of POST/PUT/DELETE troubling me the most.
The reason being, nunits don't run in order - and if they are asked to explicitly, they do not necessary wait for the previous test to finish. So how does one test against test data? e.g.
Post a testdata json
Put a testdata update
Get the testdata
Delete the testdata
so that by the end of my test I have not polluted my DB, and I have made sure all my endpoints provide with end to end functionality?
Between injecting the actual repository to set up and tear down DB entries, and what not, in the end I decided on:
[Test]
public void PostAndPutAndDeleteWorkWithoutErrors()
{
//setup
var client = JsonClient.GetClient();
var request = GenerateNewRequest();
//act post
var httpResponse = client.PostJson(uri, request );
//assert
httpResponse.StatusCode.ShouldBe(HttpStatusCode.OK);
//act put
httpResponse = client.PutJson(uri, request );
//assert
httpResponse.StatusCode.ShouldBe(HttpStatusCode.OK);
//act delete
httpResponse = client.DeleteJson(uri, request .Name);
//assert
httpResponse.StatusCode.ShouldBe(HttpStatusCode.OK);
}
Now this test tests more things than one (Post/Put/Delete), which breaks the idea of a single unit of work...
Or could one say : this does test a single unit of work - the entire cycle of posting, putting, and deleting.
Is there a better way to do this?
Thanks

does NSMetadataQueryDidUpdateNotification can work with NSFileManager setUbiquitous

i am trying to track my icloud upload progress using NSMetadataQueryDidUpdateNotification..but it can't work... i don't know what the problem is..
here is my code for upload to icloud
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fileCoordinator coordinateReadingItemAtURL:backupUrl options:NSFileCoordinatorReadingWithoutChanges error:nil byAccessor:^(NSURL *newURL) {
NSFileManager* fm = [NSFileManager defaultManager];
NSError *theError = nil;
BOOL success =[fm setUbiquitous:YES itemAtURL:backupUrl destinationURL:[[ubiq URLByAppendingPathComponent:#"Documents" isDirectory:true] URLByAppendingPathComponent:bName] error:&theError];
if (!(success)) {
[progView dismiss];
UIAlertView* alertFail=[[UIAlertView alloc]initWithTitle:#"Backup Error" message:#"Could not backup to iCloud." delegate:Nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertFail show];
NSLog(#"iCloud error: %#", [theError localizedDescription]);
}
else{
[self loadNotes:bName];
}
}];
});
and this code for tracing my upload progress
- (void)loadNotes:(NSString *)bname {
self.alertQuery = [[NSMetadataQuery alloc] init];
[self.alertQuery setPredicate:[NSPredicate predicateWithFormat:#"%K LIKE %#", NSMetadataItemFSNameKey, bname]];
[self.alertQuery setSearchScopes:#[NSMetadataQueryUbiquitousDataScope]];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(liveupdate:) name:NSMetadataQueryDidUpdateNotification object:self.alertQuery];
[self.alertQuery startQuery];
}
-(void)liveupdate:(NSNotification *)note {
NSMetadataQuery* query=[note object];
if ([query resultCount]==0){
return;
}
NSMetadataItem* item=[query resultAtIndex:0];
float progress=[[item valueForAttribute:NSMetadataUbiquitousItemPercentUploadedKey]floatValue];
[progView.progBar setProgress:progress animated:NO];
if ([[item valueForAttribute:NSMetadataUbiquitousItemIsUploadedKey] boolValue]){
[query stopQuery];
[query disableUpdates];
_alertQuery=nil;
[progView dismiss];
}
}
what is the wrong with code...
can somebody tell me what is the best way to track icloud upload progress in NSFileManager setUbiquitous....
thank you...
You will probably want to observe the NSMetadataQueryDidFinishGatheringNotification notification, which fires first, with the initial set of results.
But even then, you may not get what you want, because the update notification will only fire if the set of results changes. You are searching for a particular file, and since that file is not being deleted or anything like that, your set of results will remain the same, even if the file uploads or downloads.
In my experience, NSMetadataQuery is not very effective for monitoring upload and download progress. You can hack it to almost work, but it is never exactly what you want.
Probably the best you can do is fire the metadata query, observe the finished-gathering notification, stop the query, and start the query again. Do this at regular intervals of a second or so, and you should be able to track the progress.
You should also consider whether you really want to track progress of an individual file. It will depend how large your files are. In many cases, you may be better to track the number of files to upload/download, or the total bytes remaining.
If this is the case, you can try to setup a metadata that includes a predicate with the uploaded/downloaded status included. This will continually fire notifications when a file finishes uploading/downloading. You can find an example of this here. Look for the method startMonitoringMetadata.

how to unit-test setInterval in karma angularjs

app.directive('shuffleBlocks', function($timeout){
return {
link: function(sco,ele,att){
if (itemCnt <= 1) return;
/*Trigger function*/
function triggerEvent(){
...
}
ele.bind('click', triggerEvent);
setInterval(triggerEvent, 5000);
}
}
})
here I wrote the test
var elem = '<div shuffle-blocks><div>';
elem = mockCompile(elem)(rootScope.$new());
setInterval(function(){
expect(......).toBe(....)
});
Obviously this is not the right method,
does anyone know how to test $timeout and setInterval in karma?
UPDATE: The proper method of mocking setInterval in an angular 1.2+ application is to use angular's $interval service. Using the $interval service provides a number of benefits, but the one of most use in this situation is the $interval.flush() method. When writing tests, $interval exposes a .flush() method which allows you to mock the JS clock.
app.directive('shuffleBlocks', function($timeout, $interval){
return {
link: function(sco,ele,att){
if (itemCnt <= 1) return;
/*Trigger function*/
function triggerEvent(){ ... }
ele.bind('click', triggerEvent);
$interval(triggerEvent, 5000);
}
}
});
and then in your unit test:
var elem = '<div shuffle-blocks><div>';
elem = mockCompile(elem)(rootScope.$new());
$interval.flush(5000); // flush accepts the # of ms to be flushed
expect(......).toBe(....);
Hope that's helpful to anyone who looks up this answer in the future. I'll leave my previous answer for those still using 1.1X.
Previous Answer: According the jasmine docs, you should be able to just use the jasmine.Clock.useMock() function to mock the typical javascript clock and manually work your way through the interval. Since angular is just wrapping the native setTimeout function, I'm quite positive it should allow this to work, though I haven't tested it to be sure.
The jasmine docs for version 1.3 are here. Here's the code example that demonstrates how it works.
beforeEach(function() {
timerCallback = jasmine.createSpy('timerCallback');
jasmine.Clock.useMock();
});
it("causes a timeout to be called synchronously", function() {
setTimeout(function() {
timerCallback();
}, 100);
expect(timerCallback).not.toHaveBeenCalled();
jasmine.Clock.tick(101);
expect(timerCallback).toHaveBeenCalled();
});
The only issue I see is that your triggerEvent() function is local to your link function, so I don't know how you'll be able to get to it to mock it. But hopefully that points you in the right direction. If not, sorry, I tried.
UPDATE: The syntax for mocking the clock has changed in Jasmine 2.0. If you are using 2.0, please see the updated docs here.

test of angularjs controller: unsatistifed post request

I'm testing an angularjs controller, using also mocks, but it raises the error 'Error: Unsatisfied requests: POST /myurl
My file for test contains a beforeEach method like this
httpBackend.whenPOST('/myurl')
.respond( 200,obj1 );
httpBackend.expectPOST('/myurl')
scope = $rootScope.$new();
MainCtrl = $controller('MyCtrl', {
$scope:scope
});
and my test case is:
it('scope.mymethod should work fine', function(){
httpBackend.flush()
// verify size of array before calling the method
expect(scope.myobjs.length).toEqual(2)
// call the method
scope.saveNewPage(myobj)
// verify size of array after calling the method
expect(scope.myobjs.length).toEqual(3)
})
The method saveNewPage looks like:
function saveNewPage(p){
console.log('Hello')
$http.post('/myurl', {
e:p.e, url:p.url, name:p.name
}).then(function (response) {
otherMethod(new Page(response.data.page))
}, handleError);
}
Note that console.log('Hello') is never executed (in karma console it's never printed).
EDIT:
In the meanwhile I'm studying the doc about httpBackend, I tried to change the position of httpBackend.flush(). Basically, i'm executing a first flush(), to initialize data in the scope, then I execute the method, and then I execute an other flush() for the pending request. Specifically, in this situation the test case look like:
it('scope.saveNewPage should work fine', function(){
var p=new Object(pages[0])
httpBackend.flush()
httpBackend.whenPOST('/myurl',{
url:pages[0].url,
existingPage:new Object(pages[0]),
name:pages[0].name
}).respond(200,{data:pages[0]})
httpBackend.expectPOST('/myurl')
scope.saveNewPage(p)
httpBackend.flush()
expect(scope.pages.length).toBe(3)
})
But now it raises Error: No response defined !, like if I didn't specified the mock for that url
I solved in this way:
I put the calls of whenPOST and expectPOST before calling the method to test
I put httpBackend.flush() after calling the method to test, such that, invoking the method it generates pending request, and by httpBackend.flush() it satisfies the pending requests
I adjusted the parameter of respond method. Basically it didn't need to associate the response to a data key of the response
Assuming the POST is supposed to come from saveNewPage, you will need to call httpBackend.flush() between saveNewPage and the line where you inspect the result. flush only flushes the responses that have already been requested by your code.
it('scope.mymethod should work fine', function(){
expect(scope.myobjs.length).toEqual(2)
scope.saveNewPage(myobj)
expect(scope.myobjs.length).toEqual(2)
httpBackend.flush()
expect(scope.myobjs.length).toEqual(3)
})