无法在 XCUITest 中加载 Main.Storyboard
Could not load Main.Storyboard in XCUITest
我正在尝试为 UIViewcontrollers 制作 UITestCase,但是当我在我的 QuizAppUITests
中加载主情节提要时,它无法从 Bundle
中识别并且给出以下错误
Could not find a storyboard named 'Main' in bundle NSBundle </Users/mac/Library/Developer/CoreSimulator/Devices/CC199C69-F398-4A7C-882E-BFD3E72B95D3/data/Containers/Bundle/Application/BCC3F88D-E08C-4491-8340-699EAF98AB28/QuizAppUITests-Runner.app> (loaded) (NSInvalidArgumentException)
我也在 QuizAppUITests Target 中添加了 Main Storyboard
下面是我的测试代码
import XCTest
@testable import QuizApp
class QuizViewControllerUITests: XCTestCase {
func makeSUT() -> QuizViewController {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle(for: type(of: self)))
let sut = storyboard.instantiateViewController(withIdentifier: "QuizViewController") as! QuizViewController
_ = sut.view
return sut
}
func test_loadQuizViewController() {
let sut = makeSUT()
sut.headerQuestion = "Q1"
XCTAssertEqual(sut.headerQuestion, "Q1")
}
}
是否需要更改 QuizAppUITests
Target 的 BuildSetting?
None 这对于 UI 测试是有意义的。相反,将您的代码放入单元测试目标,即 QuizAppTests
.
我的书iOS Unit Testing by Example有一章叫做“加载视图控制器”。在那里寻找关于基于故事板的视图控制器的内容:
- 不要在测试目标中包含故事板。仅将其放在您的应用目标中。
- 然后你可以用
UIStoryboard(name: "Main", bundle: nil)
加载故事板
- 有一种无需强制转换即可实例化视图控制器的新方法。使用
instantiateViewController(identifier:)
而不是 instantiateViewController(withIdentifier:)
并将其分配给显式类型的变量。
像这样:
let sut: QuizViewController = storyboard.instantiateViewController(
identifier: "QuizViewController"
)
因为你使用class的名字作为标识符,我们甚至可以去掉字符串。这可以防止我们在编译时出现拼写错误:
let sut: QuizViewController = storyboard.instantiateViewController(
identifier: String(describing: QuizViewController.self)
)
最后,我们可以更明确地加载视图,而不是 _ = sut.view
:
sut.loadViewIfNeeded()
这连接了插座连接。
同样,所有这些都属于您的单元测试目标 QuizAppTests
,而不属于您的 UI 测试目标 QuizAppUITests
。
对于您的实际测试,不要只是在您的被测系统中分配一个 属性 并检查它是否已分配。那证明不了什么。相反,我会专注于测试:
- 网点不为零
- 与控件的交互如您所愿
- 导航有效
- 该视图外观与批准的快照相比没有变化
这一切都可以用 TDD 来完成。
我正在尝试为 UIViewcontrollers 制作 UITestCase,但是当我在我的 QuizAppUITests
中加载主情节提要时,它无法从 Bundle
中识别并且给出以下错误
Could not find a storyboard named 'Main' in bundle NSBundle </Users/mac/Library/Developer/CoreSimulator/Devices/CC199C69-F398-4A7C-882E-BFD3E72B95D3/data/Containers/Bundle/Application/BCC3F88D-E08C-4491-8340-699EAF98AB28/QuizAppUITests-Runner.app> (loaded) (NSInvalidArgumentException)
我也在 QuizAppUITests Target 中添加了 Main Storyboard 下面是我的测试代码
import XCTest
@testable import QuizApp
class QuizViewControllerUITests: XCTestCase {
func makeSUT() -> QuizViewController {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle(for: type(of: self)))
let sut = storyboard.instantiateViewController(withIdentifier: "QuizViewController") as! QuizViewController
_ = sut.view
return sut
}
func test_loadQuizViewController() {
let sut = makeSUT()
sut.headerQuestion = "Q1"
XCTAssertEqual(sut.headerQuestion, "Q1")
}
}
是否需要更改 QuizAppUITests
Target 的 BuildSetting?
None 这对于 UI 测试是有意义的。相反,将您的代码放入单元测试目标,即 QuizAppTests
.
我的书iOS Unit Testing by Example有一章叫做“加载视图控制器”。在那里寻找关于基于故事板的视图控制器的内容:
- 不要在测试目标中包含故事板。仅将其放在您的应用目标中。
- 然后你可以用
UIStoryboard(name: "Main", bundle: nil)
加载故事板
- 有一种无需强制转换即可实例化视图控制器的新方法。使用
instantiateViewController(identifier:)
而不是instantiateViewController(withIdentifier:)
并将其分配给显式类型的变量。
像这样:
let sut: QuizViewController = storyboard.instantiateViewController(
identifier: "QuizViewController"
)
因为你使用class的名字作为标识符,我们甚至可以去掉字符串。这可以防止我们在编译时出现拼写错误:
let sut: QuizViewController = storyboard.instantiateViewController(
identifier: String(describing: QuizViewController.self)
)
最后,我们可以更明确地加载视图,而不是 _ = sut.view
:
sut.loadViewIfNeeded()
这连接了插座连接。
同样,所有这些都属于您的单元测试目标 QuizAppTests
,而不属于您的 UI 测试目标 QuizAppUITests
。
对于您的实际测试,不要只是在您的被测系统中分配一个 属性 并检查它是否已分配。那证明不了什么。相反,我会专注于测试:
- 网点不为零
- 与控件的交互如您所愿
- 导航有效
- 该视图外观与批准的快照相比没有变化
这一切都可以用 TDD 来完成。