How to stub a class method with response block using OCMock - ocmock

HTTPResult *successResult = [[HTTPResult alloc] init];
successResult.success = YES;
successResult.content = #{#"key":#"value"};
id httpMock = OCMClassMock([HTTPUtility class]);
OCMStub(ClassMethod([httpMock requestWithHTTPMethod:HTTPRequestMethodGet
URLString:#"testURL"
parameters:[OCMArg any]
response:[OCMArg any]])).andDo(^(NSInvocation *invocation) {
void(^response)(HTTPResult *) = nil;
[invocation getArgument:&response atIndex:5];
response(successResult);
});
this throw EXC_BAD_ACCESS in the[OCMockObject dealloc]method and crash when the class method is invoked
what's the right way to test a class method with a specific block

It looks like you want to capture the response argument block passed into the class method (without knowing the signature of the method I can't be sure), so instead of using [OCMArg any], you can check the argument with a block. See Section 4.3 here.
[OCMArg checkWithBlock:^BOOL(id value) { /* return YES if value is ok */ }]
So in your example:
OCMStub(ClassMethod([httpMock requestWithHTTPMethod:HTTPRequestMethodGet
URLString:#"testURL"
parameters:[OCMArg any]
response:[OCMArg checkWithBlock:^BOOL(HTTPResult *response) {
response(successResult);
return YES; // Replace this with a check for whether response is valid.
}]);

Related

RxAndroid operator retryWhen is invoked but does not resubscribe

API class using Retrofit
class interface TestApi {
#GET("/path/abc/xyz")
fun get(): Single
}
UseCase class
fun getResult(): Single {
return testApi.get()
.map{ response ->
val type = response.type
when(type){
null -> throw Exception()
else -> response
}
}
.retryWhen{ throwableHandler ->
throwableHandler.flatMap {
when(it) {
is Exception() -> Flowable.error(it)
else -> Flowable.timer(3,TimeUnit.SECONDS)
}
}
}
.timeout(60, TimeUnit.SECONDS)
}
MainClass.kt
usecase.getResult()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeBy(onError = {Log.d(TAG,"Error")},
onSuccess = {Log.d(TAG,"Next")})
When app run :
If api return NULL, retryWhen() will be invoked then api is called again.
Event not timeout reached and api return Not NUL result -> onSuccess is called. This is correctly processing of retryWhen() operator in rxJava.
My Problem:
If I write some test method (to pretend API Retrofit) in MainClass.kt looks like below:
private fun testPretend(): Single<Animal> {
return Single.just(Animal)
}
MainClass.kt looks like:
testPretend()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeBy(onError = {Log.d(TAG,"Error")},
onSuccess = {Log.d(TAG,"Next")})
So event retryWhen is invoked , testPretend() method is not called again.
What is the problem here?
And what is difference between Single return by testPrerend() and Retrofit API ?
The method testPretend() is not called again because the observable that it returned is what is being resubscribed to. If you want the method to be invoked again upon resubscription, you will need to do something like this:
Single.defer( () => testPretend() )
...
.retryWhen( ... )
...;
This will invoke testPretend() upon resubscription.

BindingResult.getFieldValue() returning null in test context for a formatted value

In a spring mvc app, I submit id's and use a formatter to convert that id to an object. It works well in the container.
But in the unit test environment, I'm seeing a problem.
I mock the formatter to always return my test value, this is fine it gets injected into the ModelAttribute. But in the BindingResult, a call to result.getFieldValue("location") for example is returning null, but only in the MockMvc context.
This is the test case:
/**
* Tests the inventory update for existing inventory records.
* #throws Exception
*/
#Test
public void testUpdateExistingProductInventory() throws Exception{
logger.entry();
VariantInventory oldInventory = new VariantInventory();
oldInventory.setId(20l);
Product product = ProductBuilder.buildBasicExisting();
Location location = new Location();
location.setId(3l);
ProductVariant variant = new ProductVariant();
variant.setId(2l);
// check the formatter is working
Mockito.when(mockProductFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(product);
Product p = mockProductFormatter.parse("1", null);
Assert.assertEquals(p, product);
// check the formatter is working
Mockito.when(mockLocationFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(location);
Location l = mockLocationFormatter.parse("3", null);
Assert.assertEquals(l, location);
// check the formatter is working
Mockito.when(mockVariantFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(variant);
ProductVariant pv = mockVariantFormatter.parse("2", null);
Assert.assertEquals(pv, variant);
// check the formatter is working
Mockito.when(mockInventoryFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(oldInventory);
VariantInventory v = mockInventoryFormatter.parse("20", null);
Assert.assertEquals(v, oldInventory);
this.mockMvc.perform(MockMvcRequestBuilders.post("/ajax/products/update/inventory")
.param("product", "1")
.param("variant", "2")
.param("location", "3")
.param("status", "ACTIVE")
.param("quantityOnHand", "30.5")
.param("lowStockQuantity", "10")
.param("inventory", "20")
)
.andExpect(status().isOk());
Mockito.verify(mockInventoryService, Mockito.times(1)).updateExisting(Mockito.eq(oldInventory), Mockito.any(VariantInventory.class));
logger.exit();
}
This is the relative part of the controller:
#RequestMapping(value = "/ajax/products/update/inventory", method= RequestMethod.POST)
public #ResponseBody
AJAXResponse updateProductInventory(#ModelAttribute ProductInventoryFormWrapper formWrapper, BindingResult result,
ModelMap map) {
logger.entry();
logger.debug("Getting product data");
if (!result.hasErrors()) {
inventoryValidator.validate(formWrapper, result);
}
}
Then skipping a few items, this is the relevant validation that fails, where I am passing location as the field.
ValidationUtils.rejectIfEmptyOrWhitespace(errors, field, "required.field", new String[]{label});
The object fails to validate because of what must be a bug.
What I observe if I debug the controller is:
The object is in the FormWrapper, and the properties are there.
But in the BindingResult object, if I call 'getFieldValue('location')` which is what's being called in the spring validation code, it's returning null, and therefore the validator rejects the value.
So for some reason the binding result hasn't registered the formatted fields or something. Note that this only happens in the Unit Test, not in the container.
Does anyone know how to fix?
Quick Edit:
I've done some more debugging, and it's failing in this block of code from AbstractPropertyBindingResult. The value is okay right up until the conversionService is called to convert it. I haven't downloaded the source beyond that method, so I can't see exactly why it's failing, but somewhere in the convert method it's being turned from the proper value, to null. I presume because I'm using MockObjects, and maybe it's calling something that I haven't anticipated to return the value.
#Override
protected Object formatFieldValue(String field, Object value) {
String fixedField = fixedField(field);
// Try custom editor...
PropertyEditor customEditor = getCustomEditor(fixedField);
if (customEditor != null) {
customEditor.setValue(value);
String textValue = customEditor.getAsText();
// If the PropertyEditor returned null, there is no appropriate
// text representation for this value: only use it if non-null.
if (textValue != null) {
return textValue;
}
}
if (this.conversionService != null) {
// Try custom converter...
TypeDescriptor fieldDesc = getPropertyAccessor().getPropertyTypeDescriptor(fixedField);
TypeDescriptor strDesc = TypeDescriptor.valueOf(String.class);
if (fieldDesc != null && this.conversionService.canConvert(fieldDesc, strDesc)) {
return this.conversionService.convert(value, fieldDesc, strDesc);
}
}
return value;
}
Ok that was a tough one, so I didn't really expect anyone to answer. But here's the answer. I was right, the Mock was being called in the validation. So I had to add an additional mock method to the formatters (print):
// check the formatter is working
Mockito.when(mockInventoryFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(oldInventory);
// this was added
Mockito.when(mockInventoryFormatter.print(Mockito.any(VariantInventory.class), Mockito.any(Locale.class))).thenReturn("20");

Swift 2.0: HTTP GET error handling in Xcode 7

I'm new with xcode programming, I'm trying to implement an App in Swift 2 that makes an HTTP Get request. After upgrading xcode 7 its showing error of:
Cannot convert value of type
'(NSData!, response: NSURLResponse!, err: NSError!) -> ()'
to expected argument type
'(NSData?, NSURLResponse?, NSError?) -> Void'
(This code snippet uses the old error handling of swift 1.2.) Can anyone help me please how to implement this in Swift 2.0.
request.HTTPMethod = "GET"
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler:loadedData)
task.resume()
}
func loadedData(data:NSData!, response:NSURLResponse!, err:NSError!){
if(err != nil)
{
print(err?.description)
}
else
{
var jsonResult: NSDictionary = NSDictionary()
let httpResponse = response as! NSHTTPURLResponse
print("\(httpResponse.statusCode)")
if (httpResponse.statusCode == 200)
{
jsonResult = (try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary
print(jsonResult)
self.performSegueWithIdentifier("SuccessSignin", sender: self)
}
else if (httpResponse.statusCode == 422){
print("422 Error Occured...")
}
}
}
The method signature has changed (parameters are now optionals). Also, you have to use try enclosed in a do catch block. And avoid using forced try (with !) but prefer catching possible errors, and use if let to safely unwrap optionals. Example:
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if error != nil {
print(error!.description)
} else {
if let httpResponse = response as? NSHTTPURLResponse {
if httpResponse.statusCode == 200 {
do {
if let data = data, let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary {
print(jsonResult)
self.performSegueWithIdentifier("SuccessSignin", sender: self)
}
} catch let JSONError as NSError {
print(JSONError)
}
} else if (httpResponse.statusCode == 422) {
print("422 Error Occured...")
}
} else {
print("Can't cast response to NSHTTPURLResponse")
}
}
}
task.resume()
Here's the error message that you are receiving:
Cannot convert value of type
'(NSData!, response: NSURLResponse!, err: NSError!) -> ()'
to expected argument type
'(NSData?, NSURLResponse?, NSError?) -> Void'
As is shown in the message, the parameters for the dataTaskWithRequest's completionHandler changed from being forced unwrapped (!) to being just optionals (?).
Notice the ! versus the ?:
// old
(NSData!, response: NSURLResponse!, err: NSError!)
// new
(NSData?, NSURLResponse?, NSError?)
As a result, you need to adjust your code accordingly.
For example, your method declaration will look like this:
func loadedData(data:NSData?, response:NSURLResponse?, err:NSError?)
In addition, evaluate the method body and make sure that you are now properly unwrapping the optional parameters data, response and err.
See the NSURLSession class reference for more information.

Reflection and typeChecking for optionals

Playing with reflections in swift 2.0 i'm trying to type check a child value.
The problem: each element of the children array in the Mirror of Any item is not optional, but his type can be optional... What happens is that of course i have the child value even if the value is nil
Maybe it is not clear so i put here some code to explain better.
For convenience i defined a subscript in a Mirror extension that fetches the child object with a given label
extension Mirror {
public subscript(key: String)->Child?{
var child = children.filter {
var valid = false
if let label = $0.label {
valid = label == key
}
return valid
}.last
if child == nil,
let superMirror = superclassMirror() {
child = superMirror[key]
}
return child
}
}
perfect, now let's say i have this class
class Rule: NSObject, AProtocol {
var hello: String?
var subRule: Rule?
}
Ok, now the problem
let aRule = Rule()
let mirroredRule = Mirror(reflecting:aRule)
if let child = mirroredRule["subRule"] {
//child.value always exists
//i can't do child.value is AProtocol? because child.value is not optional
//child.value is AProtocol of course returns false
//child.dynamicType is Optional(Rule)
if let unwrapped = unwrap(child.value) where unwrapped is AProtocol {
//This of course works only if child.value is not nil
//so the unwrap function returns an unwrapped value
//this is not a definitive solution
}
}
child.value has not been initialized so it is nil, and i can't check his type using the unwrap function. I'm writing a deserializer so i need to check the var also if it is nil because in the dictionary that will be used for the deserialization it could be defined.
private func unwrap(subject: Any) -> Any? {
var value: Any?
let mirrored = Mirror(reflecting:subject)
if mirrored.displayStyle != .Optional {
value = subject
} else if let firstChild = mirrored.children.first {
value = firstChild.value
}
return value
}
I hope the problem is clear. Any suggestions?
Based on this answer, I recommend using if case Optional<Any>.some(_).
I did something recently to make sure I have at least one optional set on my struct. You can paste into playgrounds:
struct ErrorResponse: Codable {
let message: String?
let authorizationException: [String: String]?
let validationException: String?
let generalException: String?
var isValid: Bool {
var hasAtLeastOneNonNilErrorValue = false
Mirror(reflecting: self).children.forEach {
if case Optional<Any>.some(_) = $0.value {
hasAtLeastOneNonNilErrorValue = true
}
}
return hasAtLeastOneNonNilErrorValue
}
}
let errorTest = ErrorResponse(message: "some message", authorizationException: nil, validationException: nil, generalException: nil)
let errorTest2 = ErrorResponse(message: nil, authorizationException: nil, validationException: nil, generalException: nil)
print("is valid: \(errorTest.isValid)") //is valid: true
print("is valid: \(errorTest2.isValid)") //is valid: false

Adding observer for KVO without pointers using Swift

In Objective-C, I would normally use something like this:
static NSString *kViewTransformChanged = #"view transform changed";
// or
static const void *kViewTransformChanged = &kViewTransformChanged;
[clearContentView addObserver:self
forKeyPath:#"transform"
options:NSKeyValueObservingOptionNew
context:&kViewTransformChanged];
I have two overloaded methods to choose from to add an observer for KVO with the only difference being the context argument:
clearContentView.addObserver(observer: NSObject?, forKeyPath: String?, options: NSKeyValueObservingOptions, context: CMutableVoidPointer)
clearContentView.addObserver(observer: NSObject?, forKeyPath: String?, options: NSKeyValueObservingOptions, kvoContext: KVOContext)
With Swift not using pointers, I'm not sure how to dereference a pointer to use the first method.
If I create my own KVOContext constant for use with the second method, I wind up with it asking for this:
let test:KVOContext = KVOContext.fromVoidContext(context: CMutableVoidPointer)
EDIT: What is the difference between CMutableVoidPointer and KVOContext? Can someone give me an example how how to use them both and when I would use one over the other?
EDIT #2: A dev at Apple just posted this to the forums: KVOContext is going away; using a global reference as your context is the way to go right now.
There is now a technique officially recommended in the documentation, which is to create a private mutable variable and use its address as the context.
(Updated for Swift 3 on 2017-01-09)
// Set up non-zero-sized storage. We don't intend to mutate this variable,
// but it needs to be `var` so we can pass its address in as UnsafeMutablePointer.
private static var myContext = 0
// NOTE: `static` is not necessary if you want it to be a global variable
observee.addObserver(self, forKeyPath: …, options: [], context: &MyClass.myContext)
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
if context == &myContext {
…
}
else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
Now that KVOContext is gone in Xcode 6 beta 3, you can do the following. Define a global (i.e. not a class property) like so:
let myContext = UnsafePointer<()>()
Add an observer:
observee.addObserver(observer, forKeyPath: …, options: nil, context: myContext)
In the observer:
override func observeValueForKeyPath(keyPath: String!, ofObject object: AnyObject!, change: [NSObject : AnyObject]!, context: UnsafePointer<()>) {
if context == myContext {
…
} else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}
}
Swift 4 - observing contentSize change on UITableViewController popover to fix incorrect size
I had been searching for an answer to change to a block based KVO because I was getting a swiftlint warning and it took me piecing quite a few different answers together to get to the right solution. Swiftlint warning:
Block Based KVO Violation: Prefer the new block based KVO API with keypaths when using Swift 3.2 or later. (block_based_kvo).
My use case was to present a popover controller attached to a button in a Nav bar in a view controller and then resize the popover once it's showing - otherwise it would be too big and not fitting the contents of the popover. The popover itself was a UITableViewController that contained static cells, and it was displayed via a Storyboard segue with style popover.
To setup the block based observer, you need the following code inside your popover UITableViewController:
// class level variable to store the statusObserver
private var statusObserver: NSKeyValueObservation?
// Create the observer inside viewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
statusObserver = tableView.observe(\UITableView.contentSize,
changeHandler: { [ weak self ] (theTableView, _) in self?.popoverPresentationController?.presentedViewController.preferredContentSize = theTableView.contentSize
})
}
// Don't forget to remove the observer when the popover is dismissed.
override func viewDidDisappear(_ animated: Bool) {
if let observer = statusObserver {
observer.invalidate()
statusObserver = nil
}
super.viewDidDisappear(animated)
}
I didn't need the previous value when the observer was triggered, so left out the options: [.new, .old] when creating the observer.
Update for Swift 4
Context is not required for block-based observer function and existing #keyPath() syntax is replaced with smart keypath to achieve swift type safety.
class EventOvserverDemo {
var statusObserver:NSKeyValueObservation?
var objectToObserve:UIView?
func registerAddObserver() -> Void {
statusObserver = objectToObserve?.observe(\UIView.tag, options: [.new, .old], changeHandler: {[weak self] (player, change) in
if let tag = change.newValue {
// observed changed value and do the task here on change.
}
})
}
func unregisterObserver() -> Void {
if let sObserver = statusObserver {
sObserver.invalidate()
statusObserver = nil
}
}
}
Complete example using Swift:
//
// AppDelegate.swift
// Photos-MediaFramework-swift
//
// Created by Phurg on 11/11/16.
//
// Displays URLs for all photos in Photos Library
//
// #see http://stackoverflow.com/questions/30144547/programmatic-access-to-the-photos-library-on-mac-os-x-photokit-photos-framewo
//
import Cocoa
import MediaLibrary
// For KVO: https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#//apple_ref/doc/uid/TP40014216-CH7-ID12
private var mediaLibraryLoaded = 1
private var rootMediaGroupLoaded = 2
private var mediaObjectsLoaded = 3
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
var mediaLibrary : MLMediaLibrary!
var allPhotosAlbum : MLMediaGroup!
func applicationDidFinishLaunching(_ aNotification: Notification) {
NSLog("applicationDidFinishLaunching:");
let options:[String:Any] = [
MLMediaLoadSourceTypesKey: MLMediaSourceType.image.rawValue, // Can't be Swift enum
MLMediaLoadIncludeSourcesKey: [MLMediaSourcePhotosIdentifier], // Array
]
self.mediaLibrary = MLMediaLibrary(options:options)
NSLog("applicationDidFinishLaunching: mediaLibrary=%#", self.mediaLibrary);
self.mediaLibrary.addObserver(self, forKeyPath:"mediaSources", options:[], context:&mediaLibraryLoaded)
NSLog("applicationDidFinishLaunching: added mediaSources observer");
// Force load
self.mediaLibrary.mediaSources?[MLMediaSourcePhotosIdentifier]
NSLog("applicationDidFinishLaunching: done");
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
NSLog("observeValue: keyPath=%#", keyPath!)
let mediaSource:MLMediaSource = self.mediaLibrary.mediaSources![MLMediaSourcePhotosIdentifier]!
if (context == &mediaLibraryLoaded) {
NSLog("observeValue: mediaLibraryLoaded")
mediaSource.addObserver(self, forKeyPath:"rootMediaGroup", options:[], context:&rootMediaGroupLoaded)
// Force load
mediaSource.rootMediaGroup
} else if (context == &rootMediaGroupLoaded) {
NSLog("observeValue: rootMediaGroupLoaded")
let albums:MLMediaGroup = mediaSource.mediaGroup(forIdentifier:"TopLevelAlbums")!
for album in albums.childGroups! {
let albumIdentifier:String = album.attributes["identifier"] as! String
if (albumIdentifier == "allPhotosAlbum") {
self.allPhotosAlbum = album
album.addObserver(self, forKeyPath:"mediaObjects", options:[], context:&mediaObjectsLoaded)
// Force load
album.mediaObjects
}
}
} else if (context == &mediaObjectsLoaded) {
NSLog("observeValue: mediaObjectsLoaded")
let mediaObjects:[MLMediaObject] = self.allPhotosAlbum.mediaObjects!
for mediaObject in mediaObjects {
let url:URL? = mediaObject.url
// URL does not extend NSObject, so can't be passed to NSLog; use string interpolation
NSLog("%#", "\(url)")
}
}
}
}

Resources