序章 iOS自动化测试 - 为什么不推荐在自动化测试中使用单例模式

260 篇文章 0 订阅
196 篇文章 0 订阅

2024软件测试面试刷题,这个小程序(永久刷题),靠它快速找到工作了!(刷题APP的天花板)_软件测试刷题小程序-CSDN博客文章浏览阅读3.4k次,点赞86次,收藏15次。你知不知道有这么一个软件测试面试的刷题小程序。里面包含了面试常问的软件测试基础题,web自动化测试、app自动化测试、接口测试、性能测试、自动化测试、安全测试及一些常问到的人力资源题目。最主要的是他还收集了像阿里、华为这样的大厂面试真题,还有互动交流板块……_软件测试刷题小程序​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502​编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502icon-default.png?t=N7T8https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502

尽管在国内大量的代码中使用单例这种简单的方式,但在自动化测试过程中会导致很多问题。因此,在自动化测试中,不推荐使用单例模式。

什么是单例?

《设计模式:可复用面向对象软件的基础》一书(通常被称为 GOF 书籍)中描述的单例模式是一种确保一个类只有一个实例并提供全局访问点的方法。该模式规定,类本身应负责追踪其唯一的实例,并通过拦截创建新对象的请求来确保不能创建其他实例。

简而言之,单例模式就是一个可以全局访问的唯一且不变的实例。这意味着程序的任何地方都可以方便地访问这个实例,并且无论何时访问它,都会得到同一个实例。

示例代码

final class MySingleton {
    static let sharedInstance = MySingleton() // 静态常量保存唯一实例
    
    private init() {} // 私有化构造函数,确保外部无法直接实例化
    
    func someMethod() {
        print("This is a method of the singleton instance.")
    }
}

// 使用示例
let singletonInstance = MySingleton.sharedInstance
singletonInstance.someMethod() // 调用单例方法

举个例子

struct LoggedInUser {}

class ApiClient {
    static let shared = ApiClient() // 单例模式,存储唯一实例
    
    func login(completion: (LoggedInUser) -> Void) {
        // 模拟登录逻辑,实际情况应该是发送登录请求到服务器
        let loggedInUser = LoggedInUser()
        completion(loggedInUser)
    }
}

class MockApiClient: ApiClient {}

class LoginViewController: UIViewController {
    var api = ApiClient.shared // 创建一个 ApiClient 实例
    
    func didTapLoginButton() {
        api.login() { user in
            print("User logged in:", user)
        }
    }
}

单例的缺点

在测试中使用单例模式可能会导致一些问题,这些问题包括:

全局状态难以管理

单例模式提供全局共享的实例,这使得在测试中难以管理和重置状态。不同的测试可能会相互干扰,因为它们共享同一个单例实例的状态。

// 测试示例
class LoginViewControllerTests: XCTestCase {
    func testLogin() {
        let api = ApiClient.shared
        // 测试前重置单例状态
        api.reset() 
        
        // 执行测试
        let expectation = self.expectation(description: "Login")
        api.login { user in
            XCTAssertNotNil(user)
            expectation.fulfill()
        }
        waitForExpectations(timeout: 1, handler: nil)
        
        // 另一个测试
        api.reset() // 重置单例状态
        api.login { user in
            XCTAssertNotNil(user)
        }
    }
}

难以进行并行测试

由于单例实例在全局范围内是唯一的,这可能会导致测试之间的竞态条件,使得并行测试难以实现。如果一个测试修改了单例的状态,另一个同时运行的测试可能会失败,导致测试结果不可靠。

// 测试示例
class ParallelTests: XCTestCase {
    func testParallelLogin() {
        DispatchQueue.concurrentPerform(iterations: 10) { _ in
            let api = ApiClient.shared
            api.login { user in
                XCTAssertNotNil(user)
            }
        }
    }
}

测试隔离困难

单例模式使得测试难以实现隔离。测试应该是独立的,彼此之间不应有任何副作用。但是由于单例实例是共享的,一个测试的改变可能会影响到其他测试,从而违反了测试的独立性原则。

// 测试示例
class IsolatedTests: XCTestCase {
    func testIsolatedLogin() {
        let api1 = ApiClient.shared
        let api2 = ApiClient.shared
        api1.login { user in
            XCTAssertNotNil(user)
        }
        api2.login { user in
            XCTAssertNotNil(user)
        }
    }
}

重置和初始化复杂

在测试环境中需要对单例进行重置,以确保每个测试都有一个干净的初始状态。这可能需要额外的代码来处理单例实例的初始化和销毁,从而增加了测试的复杂性。

// 重置示例
class ApiClient {
    static let shared = ApiClient()
    private var loggedInUser: LoggedInUser?
    
    func reset() {
        loggedInUser = nil
    }
    
    func login(completion: (LoggedInUser) -> Void) {
        if loggedInUser == nil {
            loggedInUser = LoggedInUser()
        }
        completion(loggedInUser!)
    }
}

依赖隐藏

单例模式使得依赖关系隐式化,难以通过构造函数注入等方式来明确声明依赖。这种隐式依赖关系会使得测试时很难替换单例实例,限制了对依赖的模拟(mocking)能力。

// 依赖隐藏示例
class LoginViewController: UIViewController {
    var api = ApiClient.shared // 隐式依赖
}

增加代码耦合

单例模式会增加代码之间的耦合度,因为多个类可能会依赖于同一个单例实例。这种耦合会使得测试某个类时,必须考虑到单例类的状态和行为,从而增加了测试的复杂性。

// 代码耦合示例
class UserManager {
    func performLogin() {
        ApiClient.shared.login { user in
            print("User logged in:", user)
        }
    }
}

class UserManagerTests: XCTestCase {
    func testPerformLogin() {
        let userManager = UserManager()
        userManager.performLogin()
        // 需要考虑 ApiClient.shared 的状态
    }
}

难以扩展和维护

单例模式使得代码难以扩展和维护。如果业务逻辑发生变化,需要修改单例类,会影响到所有依赖该单例的测试,导致大量的测试需要更新。

// 难以扩展和维护示例
class ApiClient {
    static let shared = ApiClient()
    func login(completion: (LoggedInUser) -> Void) {
        // 新的登录逻辑
        let loggedInUser = LoggedInUser()
        completion(loggedInUser)
    }
}

class ExtendedApiClient: ApiClient {
    override func login(completion: (LoggedInUser) -> Void) {
        // 新的扩展逻辑
        let loggedInUser = LoggedInUser()
        completion(loggedInUser)
    }
}

总结

在自动化测试中,尽管单例模式因其简洁和便捷而被广泛使用,但其在测试过程中却带来了诸多问题。单例模式虽然能确保类只有一个实例并能全局访问,但在测试场景中,会导致依赖性问题、状态共享、难以模拟和难以重置等挑战。这些问题会增加测试用例之间的耦合度,导致测试结果的不稳定和不确定性,并且使得测试编写和执行变得更加困难。

通过避免使用单例模式,我们可以编写更健壮、更可靠的自动化测试,确保我们的代码在各种条件下都能正常运行。这不仅提高了代码质量,还增强了应用程序的稳定性和可维护性。

行动吧,在路上总比一直观望的要好,未来的你肯定会感谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入群: 759968159,里面有各种测试开发资料和技术可以一起交流哦。

最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】

​​​软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值