RxSwift Observing test cases on mocked UserDefaults - ios

I am observing for value change in userDefaults
userDefaults.rx.observe(Int.self, option.userDefaultsKey)
For unit testing I did userDefaultsMock, I am not getting how to emit when value is updated or set for those particular keys
override func setValue(_ value: Any?, forKey key: String) {
tempArray[key] = value
}

An Observable chain starts with a side effect (such as the observe(_:_:) you posted) and ends with a side effect (whatever is in the subscribe.) Everything in-between the beginning of the chain and the end is logic [1]. Move that logic to a separate function so you can test it without the mock.
[1] A couple of exceptions to this rule are do() calls and flatMap calls. Everything else is logic that needs to be tested.

Actually I couldn't mock rx.observe but did some work around to accomplish.
I used UserDefaults but with suiteName so not disturbing standard database
So this trick helped me as observable got notified.
I got idea from https://medium.com/#davidlin_98861/testing-userdefaults-cd86849fd896

Related

Mutable observable object in RxSwift or Combine

What I'm trying to achieve is to have a mutable Array in viewModel that can also be observed by Controller and reload tableView when its value changes.
I tried to use BehaviorRelay but looks like it's immutable. I can't delete and insert data inside it's value.
The best thing I managed to write is this custom ObservableObject class:
final class CustomObservableObject<T> {
var value: T {
didSet {
listener?(value)
}
}
init(value: T) {
self.value = value
}
var listener: ((T) -> Void)?
func bind(listener: #escaping ((T) -> Void)) {
self.listener = listener
}
}
which works exactly how I want. Is there anything I can use in the Combine or RxSwift framework like this class?
Thanks in advance
A BehaviorRelay is built for the specific purpose of storing state and allowing you to imperatively update it which is what you are asking for.
The BehaviorRelay type is a wrapper around the BehaviorSubject type and provides a different interface, one that does not allow the internal subject to emit an error or completed event. The Element contained in the BehaviorSubject is mutable. However, in order to mutate it you must first extract it into a var with value and then push the updated value back in with accept(_:). This will help ensure that no mutations are missed and allows you to batch up multiple mutations into a single update. These are things missing in the class you wrote.
Please always remember though:
Subjects [and Relays] provide a convenient way to poke around Rx, however they are not recommended for day to day use.
-- Introduction to Rx
As you learn more about, and grow more comfortable with, the reactive paradigm you will find yourself reaching for this particular crutch less often.

Refactoring large Swift struct with mutating functions

I'm trying to simplify a huge file in Swift and I'm not sure what would be the best approach. It might be a very naive question as I'm still fairly new to Swift :)
For the sake of simplicity, let's say I have one User struct and in it I can call a ton of different setupModeA, setupModeB and so on, called depending on various conditions:
struct User {
var currentMode: String
mutating func setupModeA() {
currentMode = "A"
}
mutating func setupModeB() {
currentMode = "B"
}
// and so on for each mode
}
I'd like to be able to take the setupMode*() functions and their associated helper functions into a separate file to make it easier to read through, since most of the time I'd be focusing on only one mode.
I was thinking:
struct ModeA {
mutating func setup() {
// change the mode from there
}
}
However I can't figure out how to simply pass and mutate the User info to this new struct.
I thought about:
initializing a bunch of ModeX objects with a user variable in the User struct and passing the User on init, but it creates weird behaviours.
using static methods on the ModeX structs, but then I'm not quite sure how to mutate the User
taking a more functional approach & not mutating the User but instead cloning it and re-assigning it each time... this would probably work but since my code is very sequencial it feels like added complexity / memory usage for nothing.
switching from struct to classes and hoping it gives me other options... but I'm afraid everything would break
really complex things that feel too weird and unintuitive to be mentioned here :)
Any pointers would be much appreciated.

What is PassthroughSubject & CurrentValueSubject

I happen to look into Apple's new Combine framework, where I see two things
PassthroughSubject<String, Failure>
CurrentValueSubject<String, Failure>
Can someone explain to me what is meaning & use of them?
I think we can make analogies with real world cases.
PassthroughSubject = A doorbell push button
When someone rings the door, you are notified only if you are at home (you are the subscriber)
PassthroughSubject doesn't have a state, it emits whatever it receives to its subscribers.
CurrentValueSubject = A light switch
Someone turns on the lights in your home when you are outside. You get back home and you know someone has turned them on.
CurrentValueSubject has an initial state, it retains the data you put in as its state.
Both PassthroughSubject and CurrentValueSubject are publishers that conform to the Subject protocol which means you can call send on them to push new values downstream at will.
The main difference is that CurrentValueSubject has a sense of state (current value) and PassthroughSubject simply relays values directly to its subscribers without remembering the "current" value:
var current = CurrentValueSubject<Int, Never>(10)
var passthrough = PassthroughSubject<Int, Never>()
current.send(1)
passthrough.send(1)
current.sink(receiveValue: { print($0) })
passthrough.sink(receiveValue: { print($0) })
You'd see that the current.sink is called immediately with 1. The passthrough.sink is not called because it has no current value. The sink will only be called for values that are emitted after you subscribe.
Note that you can also get and set the current value of a CurrentValueSubject using its value property:
current.value // 1
current.value = 5 // equivalent to current.send(5)
This isn't possible for a passthrough subject.
PassthroughSubject is used for representing events. Use it for events like button tap.
CurrentValueSubject is used representing state. Use it for storing any value, say state of switch as off and on.
Note: #Published is kind of CurrentValueSubject.
PassthroughSubject and CurrentValueSubject are both Publishers — a type introduced by Combine — that you can subscribe to (performing operations on values when values are available).
They both are designed to make it easy to transfer to using the Combine paradigm. They both have a value and an error type, and you can "send" values to them (making the values available to all subscribers)
The main difference between the two that I've seen is that CurrentValueSubject starts with a value, while PassthroughSubject does not. PassthroughSubject seems easier to grasp conceptually, at least for me.
PassthroughSubject can easily be used in place of a delegate pattern, or to convert an existing delegate pattern to Combine.
//Replacing the delegate pattern
class MyType {
let publisher: PassthroughSubject<String, Never> = PassthroughSubject()
func doSomething() {
//do whatever this class does
//instead of this:
//self.delegate?.handleValue(value)
//do this:
publisher.send(value)
}
}
//Converting delegate pattern to Combine
class MyDel: SomeTypeDelegate {
let publisher: PassthroughSubject<String, Never> = PassthroughSubject()
func handle(_ value: String) {
publisher.send(value)
}
}
Both of these examples use String as the type of the value, while it could be anything.
Hope this helps!
PassthroughSubject is suitable for event like tap action
CurrentValueSubject is suitable for state
Already a lot of good answers posted in this thread, just thought of adding this answer for someone who is coming from using RxSwift.
PassThroughSubject is like PublishSubject where it broadcasts an event to its subscribers, probably with some value passed along.
CurrentValueSubject is similar to BehaviorRelay where a single value is persisted with the subject instance and passed along during the event broadcast.

In Unit Tests how can I programmatically dismiss system permission dialog?

I have an unit test which calls methods on CNContactStore() e.g. CNContactStore().execute(saveRequest). So the permission dialog for contacts pops up, like the Push notifications alert but the contacts permission dialog doesn't get dismissed automatically. I know how to do this in UI tests with addUIInterruptionMonitor() but have no idea how to do this in unit test.
I would create a wrapper around CNContactStore and then use a mock when testing.
You're not really interested in testing CNContactStore, you are interested in testing that your code interacts with CNContactStore properly right?
Setup
I would start out creating protocols and classes to extract the contact stuff out of your "normal" code base.
First a Contact struct to hold the properties you need later to create an actual CNContact
struct Contact {
//holds whichever properties you need to create a CNContact
}
Then a protocol to hold the methods you would like to execute. This could be done with a protocol with a lot of methods like so
protocol ContactsHolder {
func save(contact: Contact)
func add(contact: Contact)
func delete(contact: Contact)
func update(contact: Contact)
//Maybe more methods, the important thing is that you abstract yourself away from CNContactStore and other Contact kit classes
}
Or you could create an enum holding the possible options like so
enum ContactsUpdateMethod {
case save(Contact)
case add(Contact)
case delete(Contact)
case update(Contact)
}
protocol ContactsHolder {
func execute(_ method: ContactsUpdateMethod)
}
In Your "Real" Code
With that in place, you are ready to create your actual ContactsHolder, which then internally uses CNContactStore and everything related to that framework.
So for instance (if you chose the version with a "pure" save function)
class CNContactsHolder: ContactsHolder {
func save(contact: Contact) {
//1. create a `CNContact` from your `Contact`
//2. create a saveRequest
//3. execute: CNContactStore().execute(saveRequest)
}
....
}
And then you give the class(es) who needs to work with CNContactStore a reference to your new ContactsHolder protocol
So in your class you have
let contactsHolder: ContactsHolder
And then you can either pass it in, in your init method
init(contactsHolder: ContactsHolder = CNContactsHolder()) {
self.contactsHolder = contactsHolder
}
Or you can declare it as a var and then give it a default value
So instead of:
let contactsHolder: ContactsHolder
You say:
var contactsHolder: ContactsHolder = CNContactsHolder()
The important thing is that you can change the ContactsHolder from being a "real" CNContactsHolder into a mock when you need to test
In Your Test Code
To test this, you create a mock:
struct MockContactsHolder: ContactsHolder {
var saveWasCalled = false
func save(contact: Contact) {
saveWasCalled = true
}
}
And then you use that in your class instead of the CNContactsHolder
Now you should be able to test your own code, without getting interrupted with permissions and stuff that is not relevant to your code, but is a consequence of using CNContactStore.
Disclaimer :)
I haven't run the above by a compiler, so there may be typos.
Also, there might be bits and pieces missing to make it fit to CNContact (callbacks and so on), but I hope you get the idea about how to split things apart.
And finally...it may seem like a lot of work, but I think it makes sense to get the "framework specific" code out into a separate helper class, hid behind a protocol, so that you can swap it out whenever you need to do testing for instance, or...if you decide to get rid of CNContact at a later point and use a different frameworks.
Hope it helps.
I think you're confusing Unit Testing with UI Testing. In Unit Testing, you just want to test, your codes (e.g. functions and properties) and with that, you'll most probably need to have "mock-up".
For instance, you want to test your login button selector that has a network calls after validation of the input fields.
The following should be the steps:
Test your validation logic. Both failing and succeeding cases.
Test the code inside the completion block of your API call, BUT not using the REAL API data. Instead, use your mocked API here.
and so on...
Now, back to your question, you don't need to handle that uncontrollable and "un-dismissable" alert controller generated by the system. Instead, what you wanna do is to "mock" (ughh not again) that pop-up event by hitting the delegate function for that access-contacts alert by the system, "mock" a response namely "Don't Allow" and "OK". What do you expect to happen when user taps on the first button? The second button? Set expectations/assert.
That's it. Hit every function you need to hit to increase the coverage of your code. Let me know if this helps.

Swift 4 Using KVO to listen to volume changes

I just updated to Swift 4 and Xcode 9 and got a (swiftlint) warning for the following code telling me that I should use KVO now:
Warning:
(Block Based KVO Violation: Prefer the new block based KVO API with
keypaths when using Swift 3.2 or later. (block_based_kvo))
The old code:
override func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {
if keyPath == "outputVolume"{
guard let newKey = change?[NSKeyValueChangeKey.newKey] as? NSNumber else {
fatalError("Could not unwrap optional content of new key")
}
let volume = newKey.floatValue
print("volume " + volume.description)
}
}
My attempt to fix:
let audioSession = AVAudioSession.sharedInstance()
audioSession.observe(\.outputVolume) { (av, change) in
print("volume \(av.outputVolume)")
}
Apple claims here that most of the properties should be dynamic (I know that this is AVPlayer and not AVAudioSession). I looked it up but couldn't find any dynamic statements inside AVPlayer properties and was wondering how that could possibly work (If I'm not mistaken those are required for KVO to work).
EDIT:
I'm not certain if it doesn't trigger because it simply doesn't work or if it's due to what I try to archive. In general I'll want to get notified on volume changes triggered by pushing the hardware-volume-rockers.
I assume you're referring to the line:
You can use Key-value observing (KVO) to observe state changes to many of the player’s dynamic properties...
This use of "dynamic" isn't the same thing as Objective-C's #dynamic or Swift's dynamic. The docs just mean "properties that change" in this context, and they're telling you that the AVPlayer is generally very KVO-compliant and intended to be observed that way. "KVO compliant" means it follows the change notification rules. There are many ways to achieve that, both automatic and manual. The docs are just promising that AVPlayer does.
(An important point about Cocoa that distinguishes it from many other systems is that Cocoa handles many things "by convention". There's no way to say in code "this is KVO compliant" and there is no way for the compiler to enforce it, but Cocoa developers tend to be very good about following the rules. When ARC was developed, it relied heavily on the fact that Cocoa developers had for years named methods following very specific rules that indicate how memory management is handled. It just added complier enforcement of the rules Cocoa developers had always followed by hand. This is why Cocoa developers get very noisy about naming conventions and capitalization. There are major parts of Cocoa that rely entirely on following consistent naming rules.)
Remembering that the AVPlayer interface is an Objective-C API that happens to be bridged to Swift, there's no equivalent of the Swift keyword dynamic in that case. That's a keyword that tells Swift that this property may be observed and so its accessors can't be optimized to static dispatch. That's not something Objective-C requires (or can do; all ObjC properties are "dynamic" in this sense).
The Objective-C #dynamic is a completely different thing, only weakly related to KVO (though it comes up in a lot of KVO-heavy contexts like Core Data). It just means "even though you can't find an accessor implementation for this property anywhere, trust me, by the time this runs an implementation will be available." This relies on the ability of ObjC's runtime to generate implementations dynamically or dispatch in programmer-controlled ways (this still kind of exists in Swift by manipulating the ObjC runtime, but it isn't really a "Swift" feature).
As for how KVO works, it's one of the few true "magic tricks" in Cocoa. For a quick intro, see Key-Value Observing Implementation Details. The short version is:
When you observe an object, a subclass for that object is dynamically created (yes, a new class is invented at runtime).
The subclass adds calls to willChangeValue... and didChangeValue... around all calls to the superclass's property accessors.
The object is "ISA-swizzled" to be that new class.
Magic! (Ok, not really magic; it's just code, but it's quite a trick.)
EDIT: The original question never mentioned that it wasn't working. The reason it's not working is because you're not assigning the returned NSKeyValueObservation in a property; you're just throwing it away. I'm surprised there's not a warning about that; I may open a radar.
When the returned NSKeyValueObservation deallocates, the observation goes away, so this creates an observation and immediately destroys it. You need to store it in a property until you want the observation to go away.
Solution by OP.
It needs to be stored in a property. Not a variable, not _ but a property. Otherwise it won't work. Like this:
class YourViewController: UIViewController {
var obs: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
let audioSession = AVAudioSession.sharedInstance()
self.obs = audioSession.observe( \.outputVolume ) { (av, change) in
print("volume \(av.outputVolume)")
}
}
}

Resources