Ios Swift Combine-publisher.CombineTest在多个线程上测试
当将publisher.CombineLatest与运行线程的发布服务器一起使用时,Ios Swift Combine-publisher.CombineTest在多个线程上测试,ios,swift,combine,Ios,Swift,Combine,当将publisher.CombineLatest与运行线程的发布服务器一起使用时,发布服务器的.sink主线程除外。CombineLatest并不总是被调用 这个问题并不是每次都会出现,这就是为什么我创建了单元测试,连续尝试测试100次。通常在4-5次迭代后失败 import XCTest import Combine class CombineLatestTests: XCTestCase { override func setUp() { continueAft
发布服务器的.sink主线程除外。CombineLatest
并不总是被调用
这个问题并不是每次都会出现,这就是为什么我创建了单元测试,连续尝试测试100次。通常在4-5次迭代后失败
import XCTest
import Combine
class CombineLatestTests: XCTestCase {
override func setUp() {
continueAfterFailure = false
}
func testCombineLatest_receiveOn() {
for x in 0...1000 {
print("---------- RUN \(x)")
let queue1 = DispatchQueue.global(qos: .userInitiated)
let queue2 = DispatchQueue.global(qos: .background)
let subj1 = PassthroughSubject<Int, Never>()
let subj2 = PassthroughSubject<Int, Never>()
let publ1 = subj1.receive(on: queue1).map { value -> Int in
print("-- Observer 1: \(value), Thread: \(Thread.current)")
return value
}
let publ2 = subj2.receive(on: queue2).map { value -> Int in
print("-- Observer 2: \(value), Thread: \(Thread.current)")
return value
}
let exp = expectation(description: "expect values")
exp.assertForOverFulfill = false
let canc = Publishers.CombineLatest(publ1, publ2)
.sink { value1, value2 in
print("-- recieved \(value1):\(value2) on \(Thread.current)")
if value1 == 10, value2 == 20 {
exp.fulfill()
}
}
subj1.send(5)
subj2.send(20)
subj1.send(10)
wait(for: [exp], timeout: 10)
canc.cancel()
}
}
func testCombineLatest_currentValue_receiveOn() {
for x in 0...100 {
print("---------- RUN \(x)")
let queue1 = DispatchQueue.global(qos: .userInitiated)
let queue2 = DispatchQueue.global(qos: .background)
let subj1 = CurrentValueSubject<Int, Never>(0)
let subj2 = CurrentValueSubject<Int, Never>(0)
let publ1 = subj1.receive(on: queue1).map { value -> Int in
print("-- Observer 1: \(value), Thread: \(Thread.current)")
return value
}
let publ2 = subj2.receive(on: queue2).map { value -> Int in
print("-- Observer 2: \(value), Thread: \(Thread.current)")
return value
}
let exp = expectation(description: "expect values")
exp.assertForOverFulfill = false
let canc = Publishers.CombineLatest(publ1,
publ2)
.sink { value1, value2 in
print("-- recieved \(value1):\(value2) on \(Thread.current)")
if value1 == 10, value2 == 20 {
exp.fulfill()
}
}
subj1.send(10)
subj2.send(20)
wait(for: [exp], timeout: 3)
canc.cancel()
}
}
func testCombineLatest_subscribeOn() {
for x in 0...100 {
print("---------- RUN \(x)")
let queue1 = DispatchQueue.global(qos: .userInitiated)
let queue2 = DispatchQueue.global(qos: .background)
let subj1 = PassthroughSubject<Int, Never>()
let subj2 = PassthroughSubject<Int, Never>()
let publ1 = subj1.map { value -> Int in
print("-- Observer 1: \(value), Thread: \(Thread.current)")
return value
}
let publ2 = subj2.map { value -> Int in
print("-- Observer 2: \(value), Thread: \(Thread.current)")
return value
}
let exp = expectation(description: "expect values")
exp.assertForOverFulfill = false
let canc = Publishers.CombineLatest(publ1, publ2)
.sink { value1, value2 in
print("-- recieved \(value1):\(value2) on \(Thread.current)")
if value1 == 10, value2 == 20 {
exp.fulfill()
}
}
queue1.async {
subj1.send(5)
subj1.send(10)
}
queue2.async {
subj2.send(20)
}
wait(for: [exp], timeout: 5)
canc.cancel()
}
}
}
导入XCTest
进口联合收割机
类CombineRelatestTests:XCTestCase{
覆盖函数设置(){
continueAfterFailure=false
}
func testcombinelatetest_receiveOn()函数{
对于0…1000中的x{
打印(“------------运行\(x)”)
让queue1=DispatchQueue.global(qos:.userInitiated)
让queue2=DispatchQueue.global(qos:.后台)
设subject1=PassthroughSubject()
设subject2=PassthroughSubject()
让publ1=subb1.receive(on:queue1.map{value->Int in
打印(“--Observer 1:\(值),Thread:\(Thread.current)”)
返回值
}
让publ2=subs2.receive(on:queue2.map{value->Int in
打印(“--Observer 2:\(值),Thread:\(Thread.current)”)
返回值
}
设exp=期望值(说明:“期望值”)
exp.assertForOverFulfill=false
让canc=publisher.CombineTest(publ1,publ2)
.sink{value1,value2 in
打印(“--received\(value1):\(value2)on\(Thread.current)”)
如果值1==10,则值2==20{
exp.fulfill()
}
}
主题1.发送(5)
2.发送(20)
主题1.发送(10)
等待(等待:[exp],超时:10)
取消
}
}
func TestCombinelateTest\u currentValue\u receiveOn()函数{
对于0…100中的x{
打印(“------------运行\(x)”)
让queue1=DispatchQueue.global(qos:.userInitiated)
让queue2=DispatchQueue.global(qos:.后台)
设SubC1=CurrentValueSubject(0)
设subs2=CurrentValueSubject(0)
让publ1=subb1.receive(on:queue1.map{value->Int in
打印(“--Observer 1:\(值),Thread:\(Thread.current)”)
返回值
}
让publ2=subs2.receive(on:queue2.map{value->Int in
打印(“--Observer 2:\(值),Thread:\(Thread.current)”)
返回值
}
设exp=期望值(说明:“期望值”)
exp.assertForOverFulfill=false
让canc=publisher.CombineTest(publ1,
publ2)
.sink{value1,value2 in
打印(“--received\(value1):\(value2)on\(Thread.current)”)
如果值1==10,则值2==20{
exp.fulfill()
}
}
主题1.发送(10)
2.发送(20)
等待(等待:[exp],超时:3)
取消
}
}
func testcombinelatetest_subscribeOn()函数{
对于0…100中的x{
打印(“------------运行\(x)”)
让queue1=DispatchQueue.global(qos:.userInitiated)
让queue2=DispatchQueue.global(qos:.后台)
设subject1=PassthroughSubject()
设subject2=PassthroughSubject()
让publ1=subb1.map{value->Int进入
打印(“--Observer 1:\(值),Thread:\(Thread.current)”)
返回值
}
让publ2=subs2.map{value->Int进入
打印(“--Observer 2:\(值),Thread:\(Thread.current)”)
返回值
}
设exp=期望值(说明:“期望值”)
exp.assertForOverFulfill=false
让canc=publisher.CombineTest(publ1,publ2)
.sink{value1,value2 in
打印(“--received\(value1):\(value2)on\(Thread.current)”)
如果值1==10,则值2==20{
exp.fulfill()
}
}
queue1.async{
主题1.发送(5)
主题1.发送(10)
}
队列2.async{
2.发送(20)
}
等待(等待:[exp],超时:5)
取消
}
}
}
下面是第三次测试的日志
Test Case '-[xxxx.CombineLatestTests testCombineLatest_currentValue_receiveOn]' started.
---------- RUN 0
-- Observer 2: 0, Thread: <NSThread: 0x6000004e0f80>{number = 9, name = (null)}
-- Observer 1: 0, Thread: <NSThread: 0x6000004f0000>{number = 7, name = (null)}
-- Observer 2: 20, Thread: <NSThread: 0x6000004f6e00>{number = 6, name = (null)}
-- recieved 0:0 on <NSThread: 0x6000004f0000>{number = 7, name = (null)}
-- Observer 1: 10, Thread: <NSThread: 0x600000439880>{number = 4, name = (null)}
-- recieved 10:20 on <NSThread: 0x600000439880>{number = 4, name = (null)}
---------- RUN 1
-- Observer 2: 0, Thread: <NSThread: 0x6000004f0000>{number = 7, name = (null)}
-- Observer 1: 0, Thread: <NSThread: 0x6000004f6e00>{number = 6, name = (null)}
-- Observer 2: 20, Thread: <NSThread: 0x6000004e0f80>{number = 9, name = (null)}
-- recieved 0:0 on <NSThread: 0x6000004f6e00>{number = 6, name = (null)}
-- Observer 1: 10, Thread: <NSThread: 0x6000004e80c0>{number = 10, name = (null)}
-- recieved 10:20 on <NSThread: 0x6000004e80c0>{number = 10, name = (null)}
---------- RUN 2
-- Observer 2: 0, Thread: <NSThread: 0x6000004f6e00>{number = 6, name = (null)}
-- Observer 1: 0, Thread: <NSThread: 0x6000004e0f80>{number = 9, name = (null)}
-- Observer 2: 20, Thread: <NSThread: 0x6000004e80c0>{number = 10, name = (null)}
-- recieved 0:0 on <NSThread: 0x6000004e0f80>{number = 9, name = (null)}
-- Observer 1: 10, Thread: <NSThread: 0x600000439880>{number = 4, name = (null)}
-- recieved 10:20 on <NSThread: 0x600000439880>{number = 4, name = (null)}
---------- RUN 3
-- Observer 2: 0, Thread: <NSThread: 0x600000439880>{number = 4, name = (null)}
-- Observer 1: 0, Thread: <NSThread: 0x6000004e0f80>{number = 9, name = (null)}
-- Observer 2: 20, Thread: <NSThread: 0x6000004f6e00>{number = 6, name = (null)}
-- recieved 0:0 on <NSThread: 0x6000004e0f80>{number = 9, name = (null)}
-- Observer 1: 10, Thread: <NSThread: 0x6000004e80c0>{number = 10, name = (null)}
-- recieved 10:20 on <NSThread: 0x6000004e80c0>{number = 10, name = (null)}
---------- RUN 4
-- Observer 1: 0, Thread: <NSThread: 0x6000004f6e00>{number = 6, name = (null)}
-- Observer 2: 0, Thread: <NSThread: 0x6000004f0000>{number = 7, name = (null)}
-- recieved 0:0 on <NSThread: 0x6000004f0000>{number = 7, name = (null)}
-- Observer 1: 10, Thread: <NSThread: 0x600000439880>{number = 4, name = (null)}
-- Observer 2: 20, Thread: <NSThread: 0x6000004e80c0>{number = 10, name = (null)}
-- recieved 10:0 on <NSThread: 0x600000439880>{number = 4, name = (null)}
CombineLatestTests.swift:93: error: : Asynchronous wait failed: Exceeded timeout of 3 seconds, with unfulfilled expectations: "expect values".
Test Suite 'CombineLatestTests' failed at 2020-03-04 20:37:24.957.
Executed 3 tests, with 3 failures (0 unexpected) in 18.159 (18.161) seconds
testcase'-[xxxx.combinelatetests testcombinelatetest\u currentValue\u receiveOn]已启动。
----------运行0
--观察者2:0,线程:{number=9,name=(null)}
--观察者1:0,线程:{number=7,name=(null)}
--观察者2:20,线程:{number=6,name=(null)}
--在{number=7,name=(null)}上收到0:0
--观察者1:10,线程:{number=4,name=(null)}
--在{number=4,name=(null)}收到10:20
----------运行1
--观察者2:0,线程:{number=7,name=(null)}
--观察者1:0,线程:{number=6,name=(null)}
--观察者2:20,线程:{number=9,name=(null)}
--在{number=6,name=(null)}上收到0:0
--观察者1:10,线程:{number=10,name=(null)}
--在{number=10,name=(null)}收到10:20
----------运行2
--观察者2:0,线程:{number=6,name=(null)}
--观察者1:0,线程:{number=9,name=(null)}
--观察者2:20,线程:{number=10,name=(null)}
--在{number=9,name=(null)}上收到0:0
--观察者1:10,线程:{number=4,name=(null)}
--在{number=4,name=(null)}收到10:20
----------运行3
--观察者2:0,线程:{number=4,name=(null)}
--观察者1:0,线程:{number=9,name=(null)}
--观察者2:20,线程:{number=6,name=(null)}
--在{number=9,name=(null)}上收到0:0
--观察者1:10,线程:{number=10,name=(null)}
--于10:20收到{number=10,name=(
func testCombineLatest_receiveOn() {
for x in 0...100 {
print("---------- RUN \(x)")
let q1 = DispatchQueue(label: "q1", qos: .background)
let q2 = DispatchQueue(label: "q2", qos: .utility, attributes: .concurrent)
let subj1 = PassthroughSubject<Int, Never>()
let subj2 = PassthroughSubject<Int, Never>()
let publ1 = subj1
.map { value -> Int in
print("-- Observer 1: \(value), Thread: \(Thread.current)")
return value
}
let publ2 = subj2
.map { value -> Int in
print("-- Observer 2: \(value), Thread: \(Thread.current)")
return value
}
let exp = expectation(description: "expect values")
exp.assertForOverFulfill = false
// you have to use the same serial queue for publishers which you like to combine
let canc = Publishers.CombineLatest(publ1.receive(on: q1), publ2.receive(on: q1))
// this just redirect it to different queue which could be even concurrent
// (it has no effect at all)
.receive(on: q2)
.sink { value1, value2 in
print("-- recieved \(value1): \(value2) on \(Thread.current)")
if value1 == 10, value2 == 20 {
exp.fulfill()
}
}
let q = DispatchQueue.global()
// the values could be updated concurently
q.async {
subj1.send(5)
}
q.async {
subj2.send(20)
}
q.async {
subj1.send(10)
}
wait(for: [exp], timeout: 10)
canc.cancel()
}
}
---------- RUN 6
-- Observer 1: 5, Thread: <NSThread: 0x6000020aec40>{number = 6, name = (null)}
-- Observer 1: 10, Thread: <NSThread: 0x6000020aec40>{number = 6, name = (null)}
-- Observer 2: 20, Thread: <NSThread: 0x6000020d1380>{number = 4, name = (null)}
-- recieved 10: 20 on <NSThread: 0x6000020aec40>{number = 6, name = (null)}
---------- RUN 7
-- Observer 1: 5, Thread: <NSThread: 0x6000020aec40>{number = 6, name = (null)}
-- Observer 2: 20, Thread: <NSThread: 0x6000020d1380>{number = 4, name = (null)}
-- Observer 1: 10, Thread: <NSThread: 0x6000020aec00>{number = 7, name = (null)}
-- recieved 5: 20 on <NSThread: 0x6000020aec00>{number = 7, name = (null)}
-- recieved 10: 20 on <NSThread: 0x6000020aec40>{number = 6, name = (null)}