GVKun编程网logo

如何测试 Swift 枚举与关联值的相等性(swift枚举类型)

29

这篇文章主要围绕如何测试Swift枚举与关联值的相等性和swift枚举类型展开,旨在为您提供一份详细的参考资料。我们将全面介绍如何测试Swift枚举与关联值的相等性的优缺点,解答swift枚举类型的相

这篇文章主要围绕如何测试 Swift 枚举与关联值的相等性swift枚举类型展开,旨在为您提供一份详细的参考资料。我们将全面介绍如何测试 Swift 枚举与关联值的相等性的优缺点,解答swift枚举类型的相关问题,同时也会为您带来7.5 Swift枚举关联值、7.6 Swift中switch提取枚举关联值、arrays – 使用关联值映射swift枚举、iOS swift 单元测试 - 如何测试进行 api 调用的函数?的实用方法。

本文目录一览:

如何测试 Swift 枚举与关联值的相等性(swift枚举类型)

如何测试 Swift 枚举与关联值的相等性(swift枚举类型)

我想测试两个 Swift 枚举值的相等性。例如:

enum SimpleToken {    case Name(String)    case Number(Int)}let t1 = SimpleToken.Number(123)let t2 = SimpleToken.Number(123)XCTAssert(t1 == t2)

但是,编译器不会编译相等表达式:

error: could not find an overload for ''=='' that accepts the supplied arguments    XCTAssert(t1 == t2)    ^~~~~~~~~~~~~~~~~~~

我是否确实定义了自己的等式运算符重载?我希望 Swift 编译器能够自动处理它,就像 Scala 和 Ocaml 一样。

答案1

小编典典

斯威夫特 4.1+

正如有帮助地指出的那样,从 Swift4.1 开始(由于SE-0185,Swift
还支持综合EquatableHashable具有关联值的枚举。

因此,如果您使用的是 Swift 4.1 或更高版本,以下内容将自动合成必要的方法,以便XCTAssert(t1 ==t2)有效。关键是将Equatable协议添加到您的枚举中。

enum SimpleToken: Equatable {    case Name(String)    case Number(Int)}let t1 = SimpleToken.Number(123)let t2 = SimpleToken.Number(123)

在 Swift 4.1 之前

正如其他人所指出的,Swift 不会自动合成必要的相等运算符。不过,让我提出一个更清洁(恕我直言)的实现:

enum SimpleToken: Equatable {    case Name(String)    case Number(Int)}public func ==(lhs: SimpleToken, rhs: SimpleToken) -> Bool {    switch (lhs, rhs) {    case let (.Name(a),   .Name(b)),         let (.Number(a), .Number(b)):      return a == b    default:      return false    }}

这远非理想——有很多重复——但至少你不需要在内部使用 if 语句进行嵌套切换。

7.5 Swift枚举关联值

7.5 Swift枚举关联值

/**

枚举相关值

可以让枚举值对应的原始值不是唯一的,而是一个变量.

每一个枚举可以是在某种模式下的一些特定值

后面加一个 元组

*/

enum LinesegmentDescriptor {

case StartAndEndPattern(start:Double,end:Double)

case StartAndLengthPattern(start:Double,length:Double)

}

var lsd = LinesegmentDescriptor.StartAndLengthPattern(start: 0.0,length: 100.0)

lsd = LinesegmentDescriptor.StartAndEndPattern(start: 0.0,end: 50.0)

print("--------->")

print(lsd)


// 利用switch提取枚举关联值

switch lsd {

case let .StartAndEndPattern(s,e):

print("start = \(s) end = \(e)")

case .StartAndLengthPattern(let s,let l):

print("start = \(s) lenght = \(l)")

}

// 输出结果: start = 0.0 end = 50.0

7.6 Swift中switch提取枚举关联值

7.6 Swift中switch提取枚举关联值

/**

枚举相关值

可以让枚举值对应的原始值不是唯一的,而是一个变量.

每一个枚举可以是在某种模式下的一些特定值

后面加一个 元组

*/

enum LinesegmentDescriptor {

case StartAndEndPattern(start:Double,end:Double)

case StartAndLengthPattern(start:Double,length:Double)

}

var lsd = LinesegmentDescriptor.StartAndLengthPattern(start: 0.0,length: 100.0)

lsd = LinesegmentDescriptor.StartAndEndPattern(start: 0.0,end: 50.0)

print("--------->")

print(lsd)

// 利用switch提取枚举关联值

switch lsd {

case let .StartAndEndPattern(s,e):

print("start = \(s) end = \(e)")

case .StartAndLengthPattern(let s,let l):

print("start = \(s) lenght = \(l)")

}

// 输出结果: start = 0.0 end = 50.0

arrays – 使用关联值映射swift枚举

arrays – 使用关联值映射swift枚举

假设我们有一个带有相关值类型的枚举.在下面的示例中,两个值类型是包含图像的简单对象和要共享的URL.

enum Content {
  case Image(ShareableImage)
  case Video(ShareableVideo)
}

现在让我们来看一系列视频和图像案例.

let media: [Content] = [*a lot of enum cases inside here*]

到目前为止,上面的所有代码都无法在代码库中以任何方式进行更改,我需要使用它.

这开始我的问题:

让我们用媒体过滤数组,只对图像情况进行过滤

let imageOnlyCases: [Content] = media.filter { item -> Bool in

        switch item {
        case .Image: return true
        default: return false
        }
    }

下一步,我想从枚举数组获取其关联值的数组

[Content] -> [ShareableImage] by using map.

所以我这样做

let shareablemages = imageOnlyCases.map { imageCase -> ShareableImage in

        switch imageCase {

        case .Image(let image): return image
        default: return  WHAT TO DO HERE?
        }
    }

你看,我有一个返回类型的问题..我知道枚举案例都是.Image ..我想要一个简单的地图.但快速的语法并没有帮助我.

有任何想法吗?

解决方法

你可以返回case.Image的图像,否则在.flatMap操作中返回nil(以“过滤掉”nil条目):

/* Example */
enum Foo {
    case Bar(Int)
    case Baz(Int)
}

let foo: [Foo] = [.Bar(1),.Bar(9),. Baz(3),.Bar(39),.Baz(5)]

/* 1. using ''switch'' */
let barOnlyValues: [Int] = foo.flatMap {
    switch $0 {
    case .Bar(let val): return val
    case _: return nil
    }}

/* 2. alternatively,as pointed out in MartinR:s answer; 
      as you''re only looking for a single case,the alternative
      ''if case let'' clause Could be preferred over ''switch'':     */
let barOnlyValuesAlt: [Int] = foo.flatMap {
    if case let .Bar(val) = $0 { return val }
    else { return nil }}                               

print(barOnlyValues) // [1,9,39]

应用于您的用例:请注意,您无需执行过滤来创建imageOnlyCases数组,因为您可以直接在媒体数组上应用上述内容:

/* 1. using switch */
let shareableImages : [ShareableImage] = media.flatMap {
    switch $0 {
    case .Image(let image): return image
    case _: return nil
    }}

/* 2. ''if case let'' alternative,as per MartinR:s suggestion */
let shareableImagesAlt : [ShareableImage] = media.flatMap {
    if case let .Image(image) = $0 { return image }
    else { return nil }}

免责声明:我无法在实践中验证您的具体用例,因为我无权访问ShareableImage类/结构.

(感谢@MartinR的建议,即.map {…} .flatMap {…}可以简化为.flatMap {…}).

iOS swift 单元测试 - 如何测试进行 api 调用的函数?

iOS swift 单元测试 - 如何测试进行 api 调用的函数?

这取决于您想要测试的 login use case 的哪个“部分”,您项目的具体 HTTPClient? (URLSession、Alamofire 等...),或此服务的实现,但我会给您一些建议。

尝试使用 DI(依赖注入)来准备声明(类、结构、函数...)以使用协议或继承进行测试(协议是大多数情况下的最佳选择)。然后,评估所有可能的响应情况。我为登录服务用例演示做了一个简单的实现。

//
//  Created by Wilmer Barrios.
//

import XCTest

// Business Logic
struct LoginResponse {
    let succeed: Bool
}

protocol LoginService {
    func login(username: String,password: String,completion: @escaping (Result<LoginResponse,Error>) -> Void)
}

// Implementation
class LoginController {
    
    // Presented values
    var presentedSucceedMessage: String?
    var presentedErrorMessage: String?
    
    // Elements (Could be textfields)
    var username: String = ""
    var password: String = ""
    
    private let service: LoginService
    
    init(service: LoginService) {
        self.service = service
    }
    
    func login() {
        service.login(username: username,password: password,completion: { [weak self] result in
            if let response = try? result.get(),response.succeed {
                self?.presentedSucceedMessage = "Login succeed!"
            } else {
                self?.presentedErrorMessage = "Login error!"
            }
        })
    }
}

class LoginControllerTests: XCTestCase {

    func test_init_doesNotLogin() {
        let (_,service) = makeSUT()
        XCTAssertEqual(service.callCount,0)
    }
    
    func test_login_doesLoadService() {
        let (sut,service) = makeSUT()
        sut.login()
        
        XCTAssertEqual(service.callCount,1)
    }
    
    func test_loginSucceed_presentsSucceedMessage() {
        let (sut,service) = makeSUT()

        sut.login()
        service.complete(result: .success(makeLoginResponse()))
        
        XCTAssertEqual(sut.presentedSucceedMessage,"Login succeed!")
        XCTAssertNil(sut.presentedErrorMessage)
    }
    
    func test_loginError_presentsErrorMessage() {
        let (sut,service) = makeSUT()

        sut.login()
        service.complete(result: .success(makeLoginResponse(succeed: false)))
        
        XCTAssertEqual(sut.presentedErrorMessage,"Login error!")
        XCTAssertNil(sut.presentedSucceedMessage)
    }
    
    func test_loginFailed_presentsErrorMessage() {
        let (sut,service) = makeSUT()

        sut.login()
        service.complete(result: .failure(makeError()))
        
        XCTAssertEqual(sut.presentedErrorMessage,"Login error!")
        XCTAssertNil(sut.presentedSucceedMessage)
    }
    
    // MARK: Helpers
    private func makeError() -> Error {
        return NSError(domain: "anyError",code: 1)
    }
    
    private func makeLoginResponse(succeed: Bool = true) -> LoginResponse {
        return LoginResponse(succeed: succeed)
    }
    
    private func makeSUT() -> (sut: LoginController,service: LoginServiceMock) {
        let service = LoginServiceMock()
        let sut = LoginController(service: service)
        return (sut,service)
    }
    
    private class LoginServiceMock: LoginService {
        var callCount: Int = 0
        private var completion: ((Result<LoginResponse,Error>) -> Void)?
        
        func login(username: String,Error>) -> Void) {
            callCount += 1
            self.completion = completion
        }
        
        // Helpers
        func complete(result: Result<LoginResponse,Error>) {
            completion?(result)
        }
    }

}

在这个例子中,您可以请求任何登录服务,可以是您自己的 API、Firebase、任何 SDK,甚至是本地的!,您只需要让服务客户端符合 LoginService 协议。即 AlamoFireLoginClientURLSessionLoginClientFirebaseLoginClient

希望能帮到你!

今天关于如何测试 Swift 枚举与关联值的相等性swift枚举类型的讲解已经结束,谢谢您的阅读,如果想了解更多关于7.5 Swift枚举关联值、7.6 Swift中switch提取枚举关联值、arrays – 使用关联值映射swift枚举、iOS swift 单元测试 - 如何测试进行 api 调用的函数?的相关知识,请在本站搜索。

本文标签: