I have a simple Cocoa Touch Framework project with Swift code only. In my unit test class I want to do mocking so I created a mock class which inherits from the type I want to mock:
func testFirstClassMocking() {
class MockSecondClass: SecondClass {
var mockedResult = "My mocked value"
override func printSecondLogEntry(logEntry: String) -> String {
return mockedResult
}
}
let mock = MockSecondClass()
var firstClass = FirstClass(secondClass: mock)
let result = firstClass.printFirstLogEntry("whatever")
XCTAssertEqual("My mocked value", result);
}
This result in a generic compiler error:
Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1
Now, when I take the nested class out of the function and nest just in my testing class - everything is great. Code compiles and my unit test runs great. Is class nesting in functions not allowed any more?
My Xcode ver: Version 6.0.1 (6A317)
EDIT: one other thing - if I remove the override of the func - the compiler has no issues. Obviously I need the override func to be able to return a value I need in my unit test when my mock object runs.
I thought you might want to know that the following 'mock' of your mock test is compiling and passing. Let me know if I missed something about your code as it is in your question. If I did not miss anything, however, then the cause of the error is something about your code that did not make into the question. Hope that helps you either find the culprit or reformulate the question:
import XCTest
class FirstClass {
let secondClass: SecondClass
init(secondClass: SecondClass) {
self.secondClass = secondClass
}
func printFirstLogEntry(entry: String) -> String {
var fullLog = self.secondClass.printSecondLogEntry(entry)
return fullLog
}
}
class SecondClass {
func printSecondLogEntry(logEntry: String) -> String {
return logEntry
}
}
class CommandLineTests: XCTestCase {
func testFirstClassMocking() {
class MockSecondClass: SecondClass {
override func printSecondLogEntry(logEntry: String) -> String {
return logEntry
}
}
let mock = MockSecondClass()
var firstClass = FirstClass(secondClass: mock)
let result = firstClass.printFirstLogEntry("whatever")
XCTAssertEqual("whatever", result);
}
}
Related
Completely rewriting this question yet again to hopefully put the focus on the issue I'm trying to solve.
We have the following class that, due to an external framework outside of our control, requires us to implement ObjCProtocolRequiringBla, like so...
class FooBase : NSObject, ObjCProtocolRequiringBla {
class var possibleValues:[String] {
// Note: Use preconditionFailure, not fatalError for things like this.
// At runtime, they both halt execution, but precondition(Failure)
// only logs the message for debug builds. Additionally,
// in debug builds it pauses in a debuggable state rather than crash.
preconditionFailure("You must override possibleValues")
}
// This satisfies the objective-c protocol requirement
final func getBla() -> Bla {
let subclassSpecificValues = type(of:self).possibleValues
return Bla(withValues:subclassSpecificValues)
}
}
class FooA : FooBase
override class var possibleValues:[String] {
return [
"Value A1",
"Value A2",
"Value A3"
]
}
}
class FooB : FooBase
override class var possibleValues:[String] {
return [
"Value B1",
"Value B2",
"Value B3",
"Value B4"
]
}
}
As you can see, possibleValues is used in the implementation of getBla(). Additionally, it has to be common to all instances of that particular subclass, hence being a class variable and not an instance variable. This is because in another place in the code, we have to retrieve all possible values across all subclasses, like so...
static func getAllPossibleValues:[String] {
return [
FooA.possibleValues,
FooB.possibleValues
].flatMap { $0 }
}
What I'm trying to figure out how to do is make the compiler complain if a subclass of FooBase does not implement possibleValues.
In other words, how can we make this report a compile-time error:
class FooC : FooBase
// Doesn't override class var possibleValues
}
Currently the only way I know of is the above, defining it in the base class with a preconditionFailure or similar, but that's a runtime check, not compile-time so it's not the best solution.
What I'm trying to figure out how to do is make the compiler complain if a subclass of FooBase does not implement possibleValues.
You can't. You can make something like possibleValues a protocol requirement and try to adopt that protocol, obviously, but if FooBase itself implements possibleValues you cannot get the compiler to complain if a subclass fails to override it. This is not a silly idea and there are probably computer languages that give you a way to do it, but Swift is not such a language. That's why the runtime solution is the best you can hope for, and that's the standard pattern, as you can see if you look at something like UIPopoverBackgroundView.
You could solve this by replacing your FooBase class with a protocol that extends NSObjectProtocol. This will force any class implementing your protocol to having to be a subclass of NSObject and also implement the properties and methods you want.
protocol foo: NSObjectProtocol {
var someProp: String {get set}
func someFunc() -> Void
}
To have the protocol being used from Objective-C one can use the #objc annotation, this works at least for simple scenarios such as sending an selector, #selector(), as a parameter.
#objc protocol foo: NSObjectProtocol {
var someProp: String {get set}
func someFunc() -> Void
}
With that the following code worked fine
class fooClass: NSObject, foo {
var someProp: String
init(someProp: String) {
self.someProp = someProp
}
func someFunc() {
print("In someFunc with property: \(someProp)")
}
func timeIt() {
let timer = Timer.scheduledTimer(timeInterval: 0,
target: self, selector: #selector(someFunc), userInfo: nil, repeats: false)
print("timer created")
timer.fire()
}
}
func main() {
let f = fooClass(someProp: "test")
f.timeIt()
}
main()
Something along these lines, perhaps? I didn't hammer out every last detail, but I think this covers a lot of your programming problem. If you'd like to discuss it further, let's start a chatroom rather than continuing to post endless comments here.
// Just to get it to compile
class Bla { init(withValues: [String]) {} }
protocol ObjCProtocolRequiringBla {}
class FooContainer : ObjCProtocolRequiringBla {
fileprivate var fooCore: FooProtocol
fileprivate init(_ fooCore: FooProtocol) { self.fooCore = fooCore }
// This satisfies the objective-c protocol requirement
final func getBla() -> Bla { return fooCore.getBla() }
}
protocol FooProtocol {
static var possibleValues:[String] { get }
func getBla() -> Bla
}
class FooA : NSObject, FooProtocol {
class var possibleValues:[String] {
return [
"Value A1",
"Value A2",
"Value A3"
]
}
func getBla() -> Bla {
return Bla(withValues: FooA.possibleValues)
}
}
class FooB : NSObject, FooProtocol {
class var possibleValues:[String] {
return [
"Value B1",
"Value B2",
"Value B3",
"Value B4"
]
}
func getBla() -> Bla {
return Bla(withValues: FooB.possibleValues)
}
}
I'm baffled by something I've run into a couple of times. I sometimes get errors similar to the following
Cannot convert value of type 'Foo!' to expected argument type 'Foo!
'
I've searched SO, but haven't really found anything that explains why Foo! isn't the same as Foo!.
Here's an example:
// FooViewModel.swift
class FooViewModel: BaseViewModel {
fileprivate var foo: Foo!
fileprivate var bar: Bar = Bar()
init!(model: Foo!) {
super.init()
foo = model
}
override init() {
super.init()
}
func setFooModel(_ model: Foo!) {
self.foo = model
}
func getFooModel() -> Foo! {
return self.foo
}
func getBar() -> Bar {
return bar
}
func getBlah() -> String {
return "Blah"
}
}
Here is the unit test that generates the error:
import XCTest
#testable import WooHoo
class FooViewModelTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testGetBar() {
var foo = Foo()
let vm = FooViewModel()
// The following line generates the error
vm.setFooModel(foo)
XCTAssertEqual("Tell us your Foo for the Bar program.", vm.getBlah())
}
}
I've tried a number of variations for vm.setFooModel(foo) to no avail, e.g. vm.setFooModel(foo!) or declaring foo as var foo: Foo! = Foo().
edit:
Note that the code above is for illustrating the issue I'm running into and is not the operational code.
I figured this out. My view model was part of the tests target. After I set it to the run target only, the issue resolved. FYI.
I have some project where I created convenient architecture for my needing and all things was fine until I encountered mysterious crashes with EXC_BAD_ACCESS at runtime. I posted here the smallest code which represents the issue and here is the explanation:
Imagine some protocol and another one which is first's child:
protocol Base {
static var key: String { get }
}
protocol BaseChild: Base {
}
And here is some simple implementation:
struct ChildEntity: BaseChild {
static var key: String {
return "key"
}
}
Then, I have some class which works with such entities:
class Worker {
static var defaultWorker: Worker? // will explain later
func work<T: Base>(entity: T) {
print(T.key)
}
}
And I also have some subclass of Worker:
class ChildWorker: Worker {
override func work<T: BaseChild>(entity: T) {
print(T.key)
}
}
So far so good. Then I added static defaultWorker var to my Worker class to make access to my default worker easier, this allows me to create an extension for my Base protocol which will work with my defaultWorker:
extension Base {
func work() {
Worker.defaultWorker?.work(entity: self)
}
}
However this generates EXC_BAD_ACCESS at runtime. Here is simple usage:
class Test {
static func run() {
let object = ChildEntity()
let worker = ChildWorker()
worker.work(entity: object) // OK here
Worker.defaultWorker = worker
object.work() // EXC_BAD_ACCESS here
}
}
I tested this on both Xcode 8 and Xcode 9 with Swift 3 and Swift 4. Please help me solve this issue
I wonder why you override func work<T: Base>(entity: T) to override func work<T: BaseChild >(entity: T)?
Is not that supposed to be override func work<T: Base>(entity: T)?
Given:
class MyGenericSuperClass<T> {
func randomMethod(param:T) {
print("SuperClass")
}
}
class MyGenericSubClass : MyGenericSuperClass<Void> {
override func randomMethod(param:Void) {
print("SubClass")
}
}
The following will compile:
class test {
init() {
let test1 = MyGenericSuperClass<Void>()
test1.randomMethod() // outputs 'SubClass'
let test2:MyGenericSuperClass<Void> = MyGenericSubClass()
test2.randomMethod() // outputs 'SubClass'
}
}
But this causes a segmentation fault 11:
class test {
init() {
let test2 = MyGenericSubClass()
test2.randomMethod()
}
}
The only difference is the storing of the subclass in a super class variable.
Is this a compiler bug or is there something else at play here?
Background:
This was coming from a Command<TArg> class with an ActionCommand : Command<Void> subclass and then MySpecificActionCommand subclass
First, you're not properly overriding randomMethod. It should be:
class MyGenericSubClass<T> : MyGenericSuperClass<Void> {
override func randomMethod(param:Void) {
print("SubClass")
}
}
As far as I can tell this should work, so I'm guessing it's a bug. Messing around a bit, it seems to be due to MyGenericSuperClass<Void>. If you change it to something else, e.g. MyGenericSuperClass<String> everything works properly.
You need to define MyGenericSubClass like this to work properly.
class MyGenericSubClass<T> : MyGenericSuperClass<T> {
override func randomMethod(param:T) {
print("SubClass")
}
}
As far as I know there is no possible solution for mocking and stubbing methods in swift like we were used in objc with OCMock, Mockito, etc.
I'm aware of technique described here. It is quite useful in some cases, but now I had a deadlock :)
I had a service layer where I had something like contracts(calling this method with this params will return that object as callback). This is one(greatly simplified) example:
class Bar
{
func toData() -> NSData
{
return NSData()
}
}
class Foo
{
class func fromData(data: NSData) -> Foo
{
return Foo()
}
}
class ServerManager
{
let sharedInstance = ServerManager()
class func send(request: NSData, response: (NSData)->())
{
//some networking code unrelated to the problem
response(NSData())
}
}
class MobileService1
{
final class func Contract1(request: Bar, callback: (Foo) -> ())
{
ServerManager.send(request.toData()) { responseData in
callback(Foo.fromData(responseData))
}
}
//Contract2(...), Contract3(...), etc
}
Therefore somewhere in the code I had following scenario:
func someWhereInTheCode(someBool: Bool, someObject: Bar)
{
if someBool
{
MobileService1.Contract1(someObject) { resultFoo in
//self.Foo = resultFoo
}
}
else
{
//MobileService1.Contract2(...)
}
}
And the question now is how the heck could I test this? Is there better(for testing) alternative for code structure without touching contracts themselves?
Better late than never I found a solution. Just make dependency injection of the MobileService1(or better of it's interface) and then mock it easily:
//declaring interface
protocol MobileServiceContracts: class {
static func Contract1(request: Bar, callback: (Foo) -> ())
}
//make implementation to conform to interface
class MobileService1 : MobileServiceContracts
{
final class func Contract1(request: Bar, callback: (Foo) -> ())
{
ServerManager.send(request.toData()) { responseData in
callback(Foo.fromData(responseData))
}
}
//Contract2(...), Contract3(...), etc
}
//inject service
func someWhereInTheCode(someBool: Bool, someObject: Bar, serviceProvider: MobileServiceContracts.Type = MobileService1.self)
{
if someBool
{
serviceProvider.Contract1(someObject) { resultFoo in
//self.Foo = resultFoo
}
}
else
{
//MobileService1.Contract2(...)
}
}
Now you can easily change service in your tests:
class MockedMobileService1: MobileServiceContracts
{
static func Contract1(request: Bar, callback: (Foo) -> ()) {
//do whatever with the mock
}
}
someWhereInTheCode(false, someObject: Bar(), serviceProvider: MockedMobileService1.self)
And the best part is with default values you can still call it the old way(not braking change):
someWhereInTheCode(false, someObject: Bar())
Meanwhile, you can do mocking with Cuckoo, which is similar to Mockito.
Example Classes:
class ExampleObject {
var number: Int = 0
func evaluate(number: Int) -> Bool {
return self.number == number
}
}
class ExampleChecker {
func check(object: ExampleObject) -> Bool {
return object.evaluate(5)
}
}
Example Test:
#testable import App
import Cuckoo
import XCTest
class ExampleCheckerTests: XCTestCase {
func testCheck() {
// 1. Arrange
let object = MockExampleObject().spy(on: ExampleObject())
stub(object) { object in
when(object.evaluate(any())).thenDoNothing()
}
let checker = ExampleChecker()
// 2. Action
checker.check(object)
// 3. Assert
_ = verify(object).number.get
verify(object).evaluate(any())
verifyNoMoreInteractions(object)
}
}
There’s a much better framework called Mockingbird.
It’s super simple to setup and dynamically builds your mocks as the application builds to run the tests. Here’s an article that explains how some of it works