断言当前线程是主线程的单元测试[iOS]

断言当前线程是主线程的单元测试[iOS],ios,swift,multithreading,unit-testing,testing,Ios,Swift,Multithreading,Unit Testing,Testing,问题是编写一个断言当前线程是主线程的单元测试有意义吗? 赞成/反对 最近我看到了单元测试,它为服务回调断言当前线程。我不确定这是否是个好主意,我相信这更像是一种集成测试。在我看来,单元测试应该独立地断言方法,并且不应该知道服务消费者的性质 在iOS中,此服务的使用者是一个UI,默认情况下,该UI具有在主线程上运行代码的约束 更新: 服务中有一个呼叫: DispatchQueue.main.async { failure(error) } DispatchQueue.main.async

问题是编写一个断言当前线程是主线程的单元测试有意义吗? 赞成/反对

最近我看到了单元测试,它为服务回调断言当前线程。我不确定这是否是个好主意,我相信这更像是一种集成测试。在我看来,单元测试应该独立地断言方法,并且不应该知道服务消费者的性质

在iOS中,此服务的使用者是一个UI,默认情况下,该UI具有在主线程上运行代码的约束

更新:


服务中有一个呼叫:

DispatchQueue.main.async {
    failure(error)
}
DispatchQueue.main.async {
    failure(error)
}

它在测试套件中运行,不会被模拟。因此,有一个延迟打破了单元测试必须快速且单元测试应与任何其他单元测试同时运行的规则。

UI层的任务是确保它只更新主线程上的UI。您希望将主线程上的工作限制在最低限度(基本上,仅限于UI工作)。您的回调很可能会进行许多其他处理。将所有这些都放在主线程上是不好的做法,只是因为这些任务的一小部分(UI更改)需要它。

UI层的工作是确保它只更新主线程上的UI。您希望将主线程上的工作限制在最低限度(基本上,仅限于UI工作)。您的回调很可能会进行许多其他处理。将所有这些都放在主线程上是不好的做法,只是因为这些任务中的一小部分(UI更改)需要它。

IMO,从单元测试的角度来看,我们不应该关注测试当前正在运行的线程。编写测试用例的目的是确保源代码的各个单元能够正常工作,因此我们应该单独关注结果,而不是关注任何其他依赖层(服务)功能;这就是为什么单元测试中存在模拟的概念!如果SUT(测试中的系统)使用了一个处理异步任务的服务,那么您应该对它进行模拟,我们再次将重点放在测试特定的源代码单元上

作为一个真实的例子,如果我们有一个视图控制器
MyViewController
,它依赖于网络层
NetworkingManager
,如下所示:

class MyViewController: UIViewController {
    let networkManager = NetworkManager()

    func doSomething() {
        networkManager.getWhatever { isSuccess in
            // here is the side effect
        }
    }
}

class NetworkManager {
    func getWhatever(callback: (Bool) -> Void) {
        //...
    }
}
在测试
doSomething
时,我们不必关心
getwhich
方法,因此我们模拟
NetworkManager
并为我们的测试提供适当的实现;在哪个线程上运行
getwhere
回调并不重要,相反,这里的断言是
doSomething
getwhere
获得成功或失败而不考虑其实现时所产生的副作用。

但是,如果需要测试异步任务,您可以使用来进行测试,但是使用它的目的应该是观察没有依赖关系的单个异步代码


我同意你的观点,它更像是一种集成测试。对于这种情况,您可以利用断言
Thread.isMainThread
属性:

返回一个布尔值,该值指示当前线程是否为主线程


依我看,从单元测试的角度来看,我们不应该把重点放在测试当前正在运行的线程上。编写测试用例的目的是确保源代码的各个单元能够正常工作,因此我们应该单独关注结果,而不是关注任何其他依赖层(服务)功能;这就是为什么单元测试中存在模拟的概念!如果SUT(测试中的系统)使用了一个处理异步任务的服务,那么您应该对它进行模拟,我们再次将重点放在测试特定的源代码单元上

作为一个真实的例子,如果我们有一个视图控制器
MyViewController
,它依赖于网络层
NetworkingManager
,如下所示:

class MyViewController: UIViewController {
    let networkManager = NetworkManager()

    func doSomething() {
        networkManager.getWhatever { isSuccess in
            // here is the side effect
        }
    }
}

class NetworkManager {
    func getWhatever(callback: (Bool) -> Void) {
        //...
    }
}
在测试
doSomething
时,我们不必关心
getwhich
方法,因此我们模拟
NetworkManager
并为我们的测试提供适当的实现;在哪个线程上运行
getwhere
回调并不重要,相反,这里的断言是
doSomething
getwhere
获得成功或失败而不考虑其实现时所产生的副作用。

但是,如果需要测试异步任务,您可以使用来进行测试,但是使用它的目的应该是观察没有依赖关系的单个异步代码


我同意你的观点,它更像是一种集成测试。对于这种情况,您可以利用断言
Thread.isMainThread
属性:

返回一个布尔值,该值指示当前线程是否为主线程


服务中有一个呼叫:

DispatchQueue.main.async {
    failure(error)
}
DispatchQueue.main.async {
    failure(error)
}
它在测试套件中运行。因此,有一个延迟打破了单元测试必须快速且单元测试应与任何其他单元测试同时运行的规则


这解释了什么是单元测试。

服务内部有一个调用:

DispatchQueue.main.async {
    failure(error)
}
DispatchQueue.main.async {
    failure(error)
}
它在测试套件中运行。因此,有一个延迟打破了单元测试必须快速且单元测试应与任何其他单元测试同时运行的规则


这解释了什么是单元测试。

我同意你的观点,只有在UI更新的情况下,在主线程上运行代码才有意义。任何其他的计算和逻辑都应该在后台线程上执行。我同意你的观点,只有在UI更新的情况下,在主线程上运行代码才有意义。任何其他计算和逻辑