Shared state in a XCTestCase class? - swift

Can I have shared states in a XCTestCase class?
class Tests: XCTestCase {
var person: Person!
override func setUp() {
person = Person()
}
override func tearDown() {
person = nil
}
func testExample() {
print("✅ testExample")
print(person)
XCTAssertTrue(true)
}
func testExample2() {
print("✅ testExample2")
print(person)
XCTAssertTrue(true)
}
}
For example in the above code I know that person object is different in the different test methods, but is it possible to have same memory location for person object in both the test methods?

There are many popular misconceptions or confusions about how tests work, so I'll just take this opportunity to set the record straight. The memory is managed in a really weird way:
Every time a test method runs, a brand-new instance of the test case class is created, and that instance stays in existence until all the test methods of every test case class have finished.
Thus, you don't need to create the Person object for the person instance variable before every test method (setUp), because you'll get a whole new Tests instance and thus a whole new Person object, before every test method, if you just say
var person: Person! = Person()
But you do need your tearDown to nilify the person instance variable after each test method, because otherwise you'll end up with lots of Person objects. That might not matter for a tiny Person but it's a good habit to get into because you can use a boatload of memory without realizing it otherwise.

Related

Calling overridden method from super Class itself

I have following setup:
class Human {
init() {
eat()
}
func eat() {
print("I eat edible stuff")
}
}
class Vegan: Human {
override init() {
super.init()
}
override func eat() {
print("No meat or dairy!!")
}
}
Now when I create instance of Vegan() then it actually calls eat() of Vegan and not Human.
let _ = Vegan()
Output:
"No meat or dairy!!" // How? Black magic? it should be "I eat edible stuff" right?
How is this possible? Since call to Human's init() goes via super shouldn't everything inside of Human's init block get executed on its own context? How it knows and called overrided method? I believed child's implementation gets changed, this is something weird.
This is a very relevant question, as different languages have different semantics.
In C++ a Vegan object would be constructed by first constructing a Human object. Any member function called in that constructor, would be dispatched to the Human's function. Then only would the Vegan part be constructed.
Swift uses a different approach. In this regard, it is important to keep in mind that Swift uses the term initialization instead of construction. The idea is that if you create a Vegan you get from the beginning a Vegan object that doesn't eat meat, even during the initialization process.
Swift makes this relatively safe, with its constraints regarding the two step initialization. Let's add some initialized variables to the class; You'll see that the swift compiler will make sure that everything must be initialized in due time to avoid any risk of initialized variable:
class Human {
var id: Int
init() {
id = 0 // all variables must be intialized before calling a function
eat()
}
func eat() {
print("I eat edible stuff")
}
}
class Vegan: Human {
var message: String
override init() {
message = "hello" // must be initialized before calling super constructor.
super.init()
}
override func eat() {
print("No meat or dairy!!")
}
}
Of course, if you use some member functions to ensure invariants that are more complex than variable initialization, it's up to you to take extra-care about those invariants.

Patterns: Singletons vs. Static vars and methods approach

I am reading a lot about the Singleton Pattern. I am currently using it to store groups of global state in my first app. I am reaching a point where I wonder which approach to implement API client classes and similar with.
Are Structs with static vars and static functions having the same issues?
To illustrate what I mean, I've tried to write the same heavily simplified and exact same(?) scenario twice.
1. A singleton being worked with by a view controller:
struct APIClientSingletonClass {
static let shared = APIClientSingletonClass()
var stateOfSomehting: Bool = true
var stateOfSomehtingMore: Bool = false
var stateNumber: CGFloat = 1234
var stateOfSomehtingComputed: CGFloat {
return stateNumber * 10
}
func convertSomethingToSomethingElse() {
// calling method in self like this:
otherMethod()
}
func otherMethod() {
// doing stuff here
}
}
// Calling APIClient from outside:
class ViewControllerTalkingToSingleton: UIViewController {
var api = APIClientSingletonClass.shared
override func viewDidLoad() {
super.viewDidLoad()
api.convertSomethingToSomethingElse()
api.stateOfSomehting = false
}
}
2. Another approach:
struct APIClientStruct {
static var stateOfSomehting: Bool = true
static var stateOfSomehtingMore: Bool = false
static var stateNumber: CGFloat = 1234
static var stateOfSomehtingComputed: CGFloat {
return stateNumber * 10
}
static func convertSomethingToSomethingElse() {
// calling method in self like this:
APIClientStruct.otherMethod()
}
static func otherMethod() {
// doing stuff here
}
}
// Calling APIClient from outside:
class ViewControllerTalkingToStruct: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
APIClientStruct.convertSomethingToSomethingElse()
APIClientStruct.stateOfSomehting = false
}
}
What do you guys think? Is approach 2 falling into the same traps that seem to make Singletons such a double-edged sword?
Any input is really appreciated!
Best from Berlin
EDIT:
This thread is pretty interesting, but I'm not sure it really relates to my question:
Difference between static class and singleton pattern?
Since there are many perspectives on this topic, let me specify:
Does my approach 2 have the same problem implications with testing and code maintainability?
A class-based singleton is the way to go, provided you accommodate for dependency injection for your tests. The way to do this is to create a single singleton for your app, called, say, DependencyManager. In your AppDelegate (or from other classes if needed), you'd create whatever controllers, network services, realm models, etc you want to hang on your DependencyManager, and then assign them to the DependencyManager. This code would be skipped by your unit tests.
Your unit tests can then access the DependencyManager (and thus instantiate the DependencyManager during first access), and populate it with mock versions of those controllers and services to whatever degree each unit test desires.
Your UIViewControllers, your MVVM view models, etc... can access the DependencyManager as a singleton, and thus get either the real controllers and services, or a mock version of them, depending on if you're running the app or unit tests.
If you're doing MVVM, I also recommend that when a UIViewController is about to create its view model class, that it first checks a special property in the DependencyManager to see if a mockViewModel exists. A single property can serve this purpose, as only one of your UIViewControllers ever would be tested at once. It'd use that property instead of creating a new view model for itself. In this way, you can mock your view models when testing each UIViewController. (There's other tricks involved to being able to prop up a single UIViewController for testing, but I won't cover that here).
Note that all of the above can work very nicely with an app that also wants to use storyboards and/or nibs. People are so down on storyboards because they can't figure out how to do dependency injection of mock services for their view controllers. Well, the above is the solution! Just make sure in your AppDelegate to load the storyboard AFTER setting up the DependencyManager. (Remove the storyboard name from your info.plist, and instantiate it yourself in AppDelegate).
I've written a few shipped apps this way, as well as some sample apps for an SDK, along with the tests. I highly recommend the approach! And be sure to write your unit tests and viewController tests either during or at least immediately after development of each such class, or you'll never get around to them!
What generally makes sinlgetons hard to test is that the singleton objects are typically always accessed directly . Because of this, you don't have a means to substitute the real singleton object (e.g. a data-store that's backed by a database) with a mock object for testing (e.g. a data-store that's backed by an easily-configurable array of predefined test data).
Using static members has the same fundamental issue. When referencing a static member directly, you don't have a means of substituting a mock object in place of the real prod implementation.
The solution to this is quite simple: don't access singleton members directly. What I do is something like this:
// An example of a dependency.
protocol DataAccessLayer {
func getData() -> [Int]
}
// A real implementation of DataAccessLayer, backed by a real production database
class ProdDB: DataAccessLayer {
static let instance = ProdDB()
private init() {}
func getData() -> [Int] {
return [1, 2, 3] // pretend this actually queries a DB
}
}
// A mcok implementation of DataAccessLayer, made for simple testing using mock data, without involving a production database.
class MockDB: DataAccessLayer {
func getData() -> [Int] {
return [1, 2, 3] // The mock *actually* hardcodes this data
}
}
// A protocol that stores all databases and services used throughout your app
protocol ServiceContextProtocol {
var dataAccessLayer: DataAccessLayer { get } // Present via protocol, either real impl or mock can go here
//var fooAPIGateway: FooAPIGateway { get }
//... add all other databases and services here
}
// The real service context, containing real databases and service gateways
class ProdServiceContext: ServiceContextProtocol {
let dataAccessLayer: DataAccessLayer = ProdDB.instance
//var fooAPIGateway: ProdFooAPIGateway { get }
//... add all other prod databases and services here
}
// A mock service context, used in testing, which provides mocked databases and service gatways
class MockServiceContext: ServiceContextProtocol {
let dataAccessLayer: DataAccessLayer = MockDB()
//var fooAPIGateway: MockFooAPIGateway { get }
//... add all other mock databases and services here
}
let debug = false // Set this true when you're running in a test context
// A global variable through which you access all other global state (databases, services, etc.)
let ServiceContext: ServiceContextProtocol = debug ? MockServiceContext() : ProdServiceContext()
// Always reference ServiceContext.dataAccessLayer, ServiceContext.fooAPIGateway, etc.
// and *never* reference ProdDB.instance of MockDB directly.
I would use a Class based Singleton. Just remember the 2 criteria for having a singleton. You want GLOBAL ACCESS and SINGLE INSTANCE in your program. There is a couple problems where struct based singleton would fail. Once you assign a struct to a new variable, Swift makes a complete copy under the hood.
Another useful snip of information can be found using this link.
What's the difference between Struct based and Class based singletons?

XCTestCase optional instance variable

Why is my optional instance variable nil when I infact set it to non-nil?
Code:
class FooTests: XCTestCase {
var foo: Int?
func test_A_setFoo() {
XCTAssertNil(foo)
foo = 1
XCTAssertNotNil(foo)
}
func test_B_fooIsNotNil() {
XCTAssertNotNil(foo)
}
}
test_A_setFoo()succeeds while test_B_fooIsNotNil() fails
From Flow of Test Execution
(emphasis added):
For each class, testing starts by running the class setup method. For each test method, a new instance of the class is allocated and its instance setup method executed. After that it runs the test method, and after that the instance teardown method. This sequence repeats for all the test methods in the class. After the last test method teardown in the class has been run, Xcode executes the class teardown method and moves on to the next class. This sequence repeats until all the test methods in all test classes have been run.
In your case, test_B_fooIsNotNil() is executed on a fresh instance,
for which the foo property is nil.
Common setup code can be put into the setUp() class method
or setUp() instance method, see
Understanding Setup and Teardown for Test Methods

Could a Swift Singleton be a class with purely class functions

This feels like the discussion stopped a couple of Swift iterations ago, but I'm curious that in the discussions, it was never suggested (or if it was I never saw it) that a singleton could just be a class with purely class functions, eg -
class MySingleton {
private static var someVar: String?
private static var someOtherVar: SomeType?
class func start() {
// etc...
}
class func doSomething() {
// etc...
}
// etc, etc...
}
Are there any good reasons why we shouldn't do this? I can't think of any.
What do you want to achieve?
In my experience your approach is fine, if
you don't want to create an instance of your class
you don't care, that someone can create an instance of your class (which does not have any benefits, but is still technically possible).
someVar and someOtherVar should contain always the same value for all instances.
Another approach is to have a sharedInstance
class MySingleton {
private(set) static var sharedInstance = MySingleton()
private var someVar: String?
private var someOtherVar: SomeType?
func start() {
// etc...
}
func doSomething() {
// etc...
}
// etc, etc...
}
This gives you more flexibility.
You can call MySingleton.sharedInstance.start() if you want to use the shared instance.
But on the other hand, you can still create your own instance like let customInstance = MySingleton, with its own values for someVar and someOtherVar.
So it really depends on what you want to achieve. If you want to be sure, that no one can create another instance with its own vars, then your approach is safer than my alternative.
In that case, you might even want to consider to make the class final, so no one can create a subclass that behaves differently.
If an object is never instantiated, it's not a singleton. There are no instances of the object, not just a single instance.
There's nothing inherently wrong with doing that, but what's the benefit?
EDIT
It strikes me that the real comparison is between a class that only has class methods and global functions.
In that comparison, the benefit I see is name-spacing. When you create class methods, you have to qualify function calls with the name of the class, so you can say
SomeClass.someMethod()
or
SomeOtherClass.someMethod()
Those are 2 distinct functions and it is obvious that they are distinct functions.
With global functions, you simply say
someMethod()
If at a future date you merge in somebody else's code that also has a global function someMethod() you will get a compiler error about a duplicate function and have to resolve it.

Testing a class which preserves its state in private variables

I am writing unit tests for my class. This class preserves its state in some private variables (which I don't want to expose publicly). So the scenario is:
If I call a method, the first time it will keep that state in private properties and call a delegate method with some result.
When I call the same method a second time, the output will be different on the basis of the previous input.
I want to cover all the cases in my tests.
One easy way is to change my private properties to public so that I can mock the previous input in unit test.
The other way is to call the same method with different inputs in the same test twice. Where the first call will keep the state and the next call will be the actual test.
But both these ways seem awkward to me, and I am not sure of the best one.
What is the best way to write unit test for this class?
protocol ZoneUpdateDetectorOutput: class {
func updateZoneState(_ state: ZoneState)
}
class ZoneUpdateDetector {
var zoneChangeTimer: TimerProtocol?
weak var delegate: ZoneUpdateDetectorOutput?
private var previousZoneState: ZoneState?
private var expectedZoneState: ZoneState?
private func updateZoneState() {
// If `expectedZoneState` is not equal to `previousZoneState` then `delegate` will be called
// Otherwise it will just skip
if expectedZoneState != previousZoneState {
delegate?.updateZoneState(expectedZoneState!)
previousZoneState = expectedZoneState
}
}
private func runNotifyZoneStateTimer() {
guard zoneChangeTimer?.isValid() == false else {
return
}
zoneChangeTimer?.start(timeInterval: 5,
onFire: { [weak self] in
guard let strongSelf = self else {
return
}
// On timer fire, it will try to update the state
strongSelf.updateZoneState()
})
}
// When zone changes, this method is invoked
// I basically want to test this method
func zoneStateChanged(_ state: ZoneState) {
expectedZoneState = state
if state != .inZone {
runNotifyZoneStateTimer()
} else {
zoneChangeTimer?.stop()
}
}
}
You should never be testing internal state; you should only test externally (publically) visible behaviour. That way, you can change implementation details of your class without breaking any contracts, and thus without breaking any tests.
So the second option is the preferred one.
After researching and discussing with some experts, I come up with the solution that if we want to test a class which preserve it's state then the functionality which is preserving the state should go under a separate class. Which will serve the same purpose as setting the variables as private. So, ZoneUpdateDetector should have a dependency for example: ZoneUpdateStatePreserver and it should keep the state which was previously inside ZoneUpdateDetector