Core Data in Unit tests with RZVinyl - ios

Just to give a bit of backdrop: I recently started working on unit tests for the code that had been developed and maintained by some other company. My intention is to write the test cases without touching the application code .
Now coming to the problem: How can one get a reference to the CoreData stack of the application within the unit tests' target. After every service call, the response is stored in the persistent store of CoreData. I want to validate it from the unit tests class. I tried accessing the CoreData stack from unit tests but for some reason it was coming as nil after the code got compiled. Here's the piece of code in my setUp method.
- (void)setUpDataBase
{
RZCoreDataStack *stack = [[RZCoreDataStack alloc] initWithModelName:#"Skillsoft"
configuration:nil
storeType:NSSQLiteStoreType
storeURL:nil
options:RZCoreDataStackOptionDeleteDatabaseIfUnreadable];
NSAssert(stack != nil, #"Failed to create CoreData stack");
stack.mainManagedObjectContext.parentContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;
[RZCoreDataStack setDefaultStack:stack];
RZCoreDataStack *setStack = [RZCoreDataStack defaultStack];
NSLog(#"setStack Details >>> %#",setStack.description);
}
+ (RZCoreDataStack *)defaultStack
{
if ( s_defaultStack == nil ) {
RZVLogInfo(#"The default stack has been accessed without being configured. Creating a new default stack with the default options.");
// // s_defaultStack = [[RZCoreDataStack alloc] initWithModelName:nil
// configuration:nil
s_defaultStack = [[RZCoreDataStack alloc] initWithModelName:#"Skillsoft"
configuration:nil
storeType:NSSQLiteStoreType
storeURL:nil
options:RZCoreDataStackOptionDeleteDatabaseIfUnreadable];
s_defaultStack.mainManagedObjectContext.parentContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;
}
return s_defaultStack;
}`
The default stack is a static variable and is coming as nil ... I am assuming that 2 sets of static variables are being created one in application scope and other in unit tests scope ... I just want to write unit test case for a method in UIView controller that, in turn, makes a service call in scope of another layer. I want to validate it by getting a reference to CoreData in app and check if the data is being persisted properly... What is the right way to proceed with that ...
I have seen a couple of StackOverflow posts which suggests to create one's own CoreData stack in the setUp method, but with that I would need to persist the data in the same stack which I don't want to do at this moment ..
I could see that app delegate gets called when your run the unit test cases which in turn initialises quite a few objects in my project ..In order to avoid that , i have made a change in the main file itself to call testing app delegate instead of app's main delegate based on the target .. So all the initializations of the objects are being done in the unit tests..
Please suggest me the right approach to proceed...
P.S For CoreData access, the application uses a third party library named RZVinyl, which kinda made things even more complex for me ..
P.P.S My English is weak, so please let me know if I'm not clear in my explanation. I will update the problem statement..

Related

How to unit test code which receives response from server

I have a code fragment which I want to unit test , this code depends upon callback from network stack on event of receipt of data. The network calls are made through a library its basically amazon iOT library, thus I am not directly interacting with iOS network framework but this library. I want to unit test this code, not sure if its possible if yes how.
Attached is the code in question
static func subscribeForData(completionCallBack:((String,NSDictionary)->())?,errorCallBack:((NSError)->())?) {
let iotDataManager = AWSIoTDataManager.default()
let defaults = UserDefaults.standard
let login = .....
iotDataManager.subscribe(toTopic: "testNode/device/"+login, qoS: .messageDeliveryAttemptedAtLeastOnce, messageCallback: {
(payload) ->Void in
let stringValue = NSString(data: payload, encoding: String.Encoding.utf8.rawValue)!
})
}
The best way you can achieve this is through Dependency Injection (DI).
DI can be used as a mean to inject both the real networking code and the "mocked" one.
In order to deal with DI you need to modify your code. In particular an instance of AWSIoTDataManager should be passed to subscribeForData method instead of hardcoding it (why do you have a static method?).
There are different approaches in order to deal with this. One is described for example in The complete guide to Network Unit Testing in Swift. I think that if you read it, you will acquire something new useful for the feature.
Your "mocked" class (I put with "" since it could be defined as a stub or a spy) would have the same API provided by the real one.
As I stated previously, Unit Tests should be fast and should NOT depend on databases, real networks requests and so on.

Trying to use Realm Object Server Tutorial

I have created an Amazon Web Services EC2 instance and deploy one of the AMIs with a Realm Object Server as its documentation explains:
https://realm.io/docs/realm-object-server/#install-realm-object-server
Once installed and created my admin user, I have completed the iOS tutorial: https://realm.io/docs/tutorials/realmtasks/, just until point 7, enough for creating task, but when I add new task in app, nothing happens. Debugging, I notice that next sentence try, is not executing:
let items = self.items
try! items.realm?.write {
items.insert(Task(value: ["text": text]), at: items.filter("completed = false").count)
}
The items collection seems to be initialized properly:
In the ROS dashboard, can see the database referenced in Xcode:
In image can be see "Default permissions" property is no access, is this the reason of not creating new task? If so, how can I change that permissions? If that is not the reason, anyone could help me?
thanks in advance
The problem was that I did not follow al the complete tutorial because I do not want to use the desktop application, just mobile example, but realm init objects in desktop app, so I never got a valid realm where perform actions.
For a quick and simple start with this realm tutorial pointing to an online server, not local, you must initialize the TaskList object and add it to self.realm on setup
// Show initial tasks
func updateList() {
if self.realm.objects(TaskList.self).count == 0 {
let list = TaskList()
list.id = "000001"
list.text = "lista de prueba"
// Add to the Realm inside a transaction
try! self.realm.write {
self.realm.add(list)
}
}
if self.items.realm == nil, let list = self.realm.objects(TaskList.self).first {
self.items = list.items
}
self.tableView.reloadData()
}
checking if there is not a TaskList with if self.realm.objects(TaskList.self).count == 0 {, you can create one and init realm.
You probably forgot to launch Mac demo app first or login with a different user. The tutorial assumes that existing data will be synced at login. If you have never launched the Mac app or logged in a different user, it may happen that items are not managed by Realm.
The tutorial says the following:
First, please follow the Get Started instructions to get set up with the Realm Mobile Platform and to launch the macOS version of RealmTasks.
Also, you attempt to try this tutorial with ROS on AWS. The tutorial assumes running ROS on a same local machine.
So you should modify the Mac app code to connect to the AWS, then run it to synchronize the initial data. Then run the tutorial iOS app.
The default permissions here show whether all other users can access the Realm or not, which isn't the case here. We already have an internal issue around clarifying this.
The registered user who owns the Realm has individual permissions to it by default. If you wouldn't have permissions opening the synchronized Realm from the client would also fail because of insufficient permissions, so this isn't the problem here.
So going back to your code:
try! items.realm?.write { … }
My guess would be that the problem here is that the collection isn't already attached to a Realm, so that items.realm? evaluates to null. In that case the write transaction wouldn't be executed.
You can resolve this by making sure to add the items first to a Realm or executing the write directly on a synchronized Realm.

FMDB ResultSet always returns only one row

I am trying to use a sqlite database in one of my projects.
It was working fine; but for a reason, something happened and I couldn't find that bug.
The resultSet object always quit from after the first record.
The array always has only 1 record in it. (Probably it left the while because of the error)
I created a DBManager class, and this DBManager class contains different inner Classes. I have a private global FMDatabase instance (And I initialise it somewhere before using it)
As you see, there are 2 different print error line
When I run, the second print line gives this error:
Error calling sqlite3_step (21: out of memory) rs
Error Domain=FMDatabase Code=7 "out of memory" UserInfo=0x790308d0 {NSLocalizedDescription=out of memory}
And the array which should contain over 300 records, has only 1 record in it.
(Last print line is always 1)
This part is looking simple. (I have totally similar code somewhere else, but it works fine)
private var database : FMDatabase!
class DBManager{
class Element{
class func get()->[DataElement]{
database.open()
println( database.lastError() )
var result = [DataElement]()
var resultSet: FMResultSet! = database!.executeQuery("SELECT * FROM Element WHERE working = 1", withArgumentsInArray: nil)
while resultSet.next( ) {
let data = DataElement(
id : Int(resultSet.intForColumn("id")),
name: resultSet.stringForColumn("name"),
server: resultSet.stringForColumn("server"),
working: resultSet.boolForColumn("working") )
result.append( data )
}
println( database.lastError() )
database.close()
println( result.count )
return result
}
}
}
PS: Only difference between those tables is (as I realize ) the "id" column. This Element table has an "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, but the other one does not have any id column. But both of them worked well for a long time.
The "out of memory" error is a misleading SQLite error that means that a SQLite function was called with a NULL value for the sqlite3* pointer. In FMDB this means that you closed the database but then tried to continue using the same FMDatabase instance (without calling open again).
Now, I don't see you doing that in this code sample, but this code sample is employing some practices that make that sort of error possible. Namely, rather than instantiating the FMDatabase object locally, you are using some database property and you run the risk that some other function may have used it (maybe the init method for DataElement? maybe some other function that you removed for the sake of brevity? maybe some other thread?).
Let's imagine that this function called some other function that opened the database again (which FMDB will silently let you do, basically returning immediately if the database is already open), perform some SQL, and then closed the database, then this routine, when it went to retrieve the second row of information, would of have found the database closed, resulting in the error you describe. The opening and closing of the database object is not recursive. Once the subroutine closed it, it's completely closed.
Now all of this is hypothetical, because without seeing what the rest of your code does, it's impossible for me to confirm. But its a scenario that would fit what code you have shared combined with the the symptoms you've described.
Assuming that this is really the case, there are two possible solutions here:
You could simply open the database once and leave it open until the app is terminated. This is probably the easiest approach and is probably more efficient than what you have here. SQLite is actually pretty robust in terms of committing individual SQL statements (or transactions), so people usually leave the database open.
I might even go step further, and suggest that if you might have different threads interacting with this database, that you instantiate a single FMDatabaseQueue object, and use that throughout the app, again not opening and closing all the time. Note, if you use FMDatabaseQueue, you'll want to be even more judicious about making sure that one function that is in the middle of an inDatabase or inTransaction block doesn't call another function that tries to do another inDatabase or inTransaction block (or else you'll deadlock). But like any shared resource, you want to be sensitive to where a resource is locked and when it's released, and databases are no exception to that rule.
If you're determined to open and close the database in every function like this code sample suggests (again, a practice I wouldn't advise), then do not use a class property to keep track of the database. Sure, have some function that opens the database, but return this FMDatabase object, and each function would have it's own local instance and would close that instance when it's done with it.
But you really want to avoid the unintended consequences of one function's closing the database affecting the behavior of some other function.
i also faced the same issue, as after deleting the records from the table i am closing the connection and after some time i am calling one more sql query, at that point of time i got the same issue
"FMDatabase Code=7 "out of memory" UserInfo=0x790308d0 {NSLocalizedDescription=out of memory}"
just add one line of code before closing the connection ie.,
database = nil
database.close()
Later add the method in your modal class as per below
func openDatabase() -> Bool {
if database == nil {
if !FileManager.default.fileExists(atPath: pathToDatabase) {
let documentsDirectory = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString) as String
pathToDatabase = documentsDirectory.appending("/\(databaseFileName)")
print(pathToDatabase)
}
database = FMDatabase(path: pathToDatabase)
}
if !database.isOpen {
database.open()
}
return true
}
Before executing any query check this,
if openDatabase() {
//Query
}
It solved my issue.

Stubbing/mocking up webservices for an iOS app

I'm working on an iOS app whose primary purpose is communication with a set of remote webservices. For integration testing, I'd like to be able to run my app against some sort of fake webservices that have a predictable result.
So far I've seen two suggestions:
Create a webserver that serves static results to the client (for example here).
Implement different webservice communication code, that based on a compile time flag would call either webservices or code that would load responses from a local file (example and another one).
I'm curious what the community thinks about each of this approaches and whether there are any tools out there to support this workflow.
Update: Let me provide a specific example then. I have a login form that takes a username and password. I would like to check two conditions:
wronguser#blahblah.com getting login denied and
rightuser#blahblah.com logging in successfully.
So I need some code to check the username parameter and throw an appropriate response at me. Hopefully that's all the logic that I need in the "fake webservice". How do I manage this cleanly?
I'd suggest to use Nocilla. Nocilla is a library for stubbing HTTP requests with a simple DSL.
Let's say that you want to return a 404 from google.com. All you have to do is:
stubRequest(#"GET", "http://www.google.com").andReturn(404); // Yes, it's ObjC
After that, any HTTP to google.com will return a 404.
A more complete example, where you want to match a POST with a certain body and headers and return a canned response:
stubRequest(#"POST", #"https://api.example.com/dogs.json").
withHeaders(#{#"Accept": #"application/json", #"X-CUSTOM-HEADER": #"abcf2fbc6abgf"}).
withBody(#"{\"name\":\"foo\"}").
andReturn(201).
withHeaders(#{#"Content-Type": #"application/json"}).
withBody(#"{\"ok\":true}");
You can match any request and fake any response. Check the README for more details.
The benefits of using Nocilla over other solutions are:
It's fast. No HTTP servers to run. Your tests will run really fast.
No crazy dependencies to manage. On top of that, you can use CocoaPods.
It's well tested.
Great DSL that will make your code really easy to understand and maintain.
The main limitation is that it only works with HTTP frameworks built on top of NSURLConnection, like AFNetworking, MKNetworkKit or plain NSURLConnection.
Hope this helps. If you need anything else, I'm here to help.
I am assuming you are using Objective-C. For Objective-C OCMock is widely used for mocking/unit testing (your second option).
I used OCMock for the last time more than a year ago, but as far as I remember it is a fully-fledged mocking framework and can do all the things that are described below.
One important thing about mocks is that you can use as much or as little of the actual functionality of your objects. You can create an 'empty' mock (which will have all the methods is your object, but will do nothing) and override just the methods you need in your test. This is usually done when testing other objects that rely on the mock.
Or you can create a mock that will act as your real object behaves, and stub out some methods that you do not want to test at that level (e.g. - methods that actually access the database, require network connection, etc.). This is usually done when you are testing the mocked object itself.
It is important to understand that you do not create mocks once and for all. Every test can create mocks for the same objects anew based on what is being tested.
Another important thing about mocks is that you can 'record' scenarious (sequences of calls) and your 'expectations' about them (which methods behind the scenes should be called, with which parameters, and in which order), then 'replay' the scenario - the test will fail if the expectations were not met. This is the main difference between classical and mockist TDD. It has its pros and cons (see Martin Fowler's article).
Let's now consider your specific example (I'll be using pseudo-syntax that looks more like C++ or Java rather than Objective C):
Let's say you have an object of class LoginForm that represents the login information entered. It has (among others) methods setName(String),setPassword(String), bool authenticateUser(), and Authenticator* getAuthenticator().
You also have an object of class Authenticator which has (among others) methods bool isRegistered(String user), bool authenticate(String user, String password), and bool isAuthenticated(String user).
Here's how you can test some simple scenarios:
Create MockLoginForm mock with all methods empty except for the four mentioned above. The first three methods will be using actual LoginForm implementation; getAuthenticator() will be stubbed out to return MockAuthenticator.
Create MockAuthenticator mock that will use some fake database (such as an internal data structure or a file) to implement its three methods. The database will contain only one tuple: ('rightuser','rightpassword').
TestUserNotRegistered
Replay scenario:
MockLoginForm.setName('wronuser');
MockLoginForm.setPassword('foo');
MockLoginForm.authenticate();
Expectations:
getAuthenticator() is called
MockAuthenticator.isRegistered('wrognuser') is called and returns 'false'
TestWrongPassword
Replay scenario:
MockLoginForm.setName('rightuser');
MockLoginForm.setPassword('foo');
MockLoginForm.authenticate();
Expectations:
getAuthenticator() is called
MockAuthenticator.isRegistered('rightuser') is called and returns 'true'
MockAuthenticator.authenticate('rightuser','foo') is called and returns 'false'
TestLoginOk
Replay scenario:
MockLoginForm.setName('rightuser');
MockLoginForm.setPassword('rightpassword');
MockLoginForm.authenticate();
result = MockAuthenticator.isAuthenticated('rightuser')
Expectations:
getAuthenticator() is called
MockAuthenticator.isRegistered('rightuser') is called and returns 'true'
MockAuthenticator.authenticate('rightuser','rightpassword') is called and returns 'true'
result is 'true'
I hope this helps.
You can make a mock web service quite effectively with a NSURLProtocol subclass:
Header:
#interface MyMockWebServiceURLProtocol : NSURLProtocol
#end
Implementation:
#implementation MyMockWebServiceURLProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
return [[[request URL] scheme] isEqualToString:#"mymock"];
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
return request;
}
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b
{
return [[a URL] isEqual:[b URL]];
}
- (void)startLoading
{
NSURLRequest *request = [self request];
id <NSURLProtocolClient> client = [self client];
NSURL *url = request.URL;
NSString *host = url.host;
NSString *path = url.path;
NSString *mockResultPath = nil;
/* set mockResultPath here … */
NSString *fileURL = [[NSBundle mainBundle] URLForResource:mockResultPath withExtension:nil];
[client URLProtocol:self
wasRedirectedToRequest:[NSURLRequest requestWithURL:fileURL]
redirectResponse:[[NSURLResponse alloc] initWithURL:url
MIMEType:#"application/json"
expectedContentLength:0
textEncodingName:nil]];
[client URLProtocolDidFinishLoading:self];
}
- (void)stopLoading
{
}
#end
The interesting routine is -startLoading, in which you should process the request and locate the static file corresponding to the response in the app bundle before redirecting the client to that file URL.
You install the protocol with
[NSURLProtocol registerClass:[MyMockWebServiceURLProtocol class]];
And reference it with URLs like
mymock://mockhost/mockpath?mockquery
This is considerably simpler than implementing a real webservice either on a remote machine or locally within the app; the tradeoff is that simulating HTTP response headers is much more difficult.
OHTTPStubs is a pretty great framework for doing what you want that's gained a lot of traction. From their github readme:
OHTTPStubs is a library designed to stub your network requests very easily. It can help you:
Test your apps with fake network data (stubbed from file) and simulate slow networks, to check your application behavior in bad network conditions
Write Unit Tests that use fake network data from your fixtures.
It works with NSURLConnection, new iOS7/OSX.9's NSURLSession, AFNetworking (both 1.x and 2.x), or any networking framework that use Cocoa's URL Loading System.
OHHTTPStubs headers are fully documented using Appledoc-like / Headerdoc-like comments in the header files. You can also read the online documentation here.
Here's an example:
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
return [request.URL.host isEqualToString:#"mywebservice.com"];
} withStubResponse:^OHHTTPStubsResponse*(NSURLRequest *request) {
// Stub it with our "wsresponse.json" stub file
NSString* fixture = OHPathForFileInBundle(#"wsresponse.json",nil);
return [OHHTTPStubsResponse responseWithFileAtPath:fixture
statusCode:200 headers:#{#"Content-Type":#"text/json"}];
}];
You can find additional usage examples on the wiki page.
As far as option 1, I have done this in the past using CocoaHTTPServer and embedding the server directly in an OCUnit test:
https://github.com/robbiehanson/CocoaHTTPServer
I put up the code for using this in a unit test here:
https://github.com/quellish/UnitTestHTTPServer
After all, HTTP is by design just request/response.
Mocking a web service, wether by creating a mock HTTP server or creating a mock web service in code, is going to be about the same amount of work. If you have X code paths to test, you have at least X code paths to handle in your mock.
For option 2, to mock the web service you would not be communicating with the web service, you would be instead be using the mock object which has known responses.
[MyCoolWebService performLogin:username withPassword:password]
would become, in your test
[MyMockWebService performLogin:username withPassword:password]
The key point being that MyCoolWebService and MyMockWebService implement the same contract (in objective-c, this would be a Protocol). OCMock has plenty of documentation to get you started.
For an integration test though, you should be testing against the real web service, such as a QA/staging environment. What you are actually describing sounds more like functional testing than integration testing.

NSZombie created with -Os and Automatic Reference Counting in iOS 5 development

I spent the day working on a strange error in my iOS 5 iPad application, and I was wondering if anyone had some information.
Here's the general setup: There's a UIViewController subclass StoryViewChildController that has two member variables: _currentModel and _comingModel. There is a method in StoryViewChildController that calls [[INEWSStoryModel alloc] init] and returns the resulting object that was created. During viewDidLoad, I have the following code block. Note that this isn't verbatim copied from the code - it's more complicated - but I'm trying to summarize:
_currentModel = [self createModel];
_comingModel = [self createModel];
Then, at some point, I need to be able to swap _currentModel and _comingModel, along with other objects. Here is the swap method, verbatim from my code:
- (void)swapComingPageAndCurrentPage {
[_swapLock lock];
//Swap story views
IPCStoryView *swapPage = _currentPage;
_currentPage = _comingPage;
_comingPage = swapPage;
//Swap models
INEWSStoryModel *swapModel = _currentModel;
_currentModel = _comingModel;
_comingModel = swapModel;
//Swap players
PlayerController *swapPlayer = _currentPlayerController;
_currentPlayerController = _comingPlayerController;
_comingPlayerController = swapPlayer;
// clear out the content of the old view
[_comingPage resetStoryView];
[_comingPlayerController resetPlayer];
_comingPlayerController.view.alpha = 0.0;
_currentPageURI = _lastRequestedStory;
[_swapLock unlock];
}
The problem is: when I'm run my project in Release configuration (which uses -Os for compiler optimization) I crash during the swap of the model objects. The crash comes from attempting to access a Zombie object. I used Instruments to track down the retain/release path of my objects, and coming into this method, _currentModel has a reference count of 1, as expected. However, the line INEWSStoryModel *swapModel = _currentModel; does NOT cause a retain to be called on _currentModel, so the next call _currentModel = _comingModel;, causes the reference count to drop to 0. Then, when swapModel falls out of scope, another release call is attempted, and the program crashes.
It almost seems to me that the compiler optimization is optimizing away retain calls that it should not. Has anyone else had this type of problem? Could I be doing something else wrong? If necessary I can post more code from the class.
Other interesting notes: If I set the swapModel variable as __autoreleasing, the code works. Also, if I add the following code block at the end of the swap method, the code works:
_comingPage.cueView.frame = [_comingPage adjustCueViewFrame:_comingPage.cueView.frame
ForVideoShowing: NO
inOrientation:_currentOrientation];
All that method does is adjust a UIView frame. The fact that I can add unrelated code to the end of the method and have it not create a zombie leads me to think the compiler is optimizing incorrectly. Anyone have any ideas?

Resources