我对单元测试很陌生,我一直在为测试私有功能的正确方法而奋斗。我已经做了我的研究,并将通过公共接口进行测试。
我的问题是,如果我有一个由两个公共函数使用的私有函数,我会遇到测试用例副本,我不知道如何克服这些问题。在所面临的情况下,将私有函数提取到另一个类似乎不合适,因为该函数仅足以使类使用它。
示例:
// This function is called only once, once the view is loaded
override func handleViewDidLoad() {
super.handleViewDidLoad()
loadData()
// I have extra setup code in here
}
// This function is called when user double taps on the screen
override func handleReloadData() {
super.handleReloadData()
loadData()
}
private func loadData() {
delegate.showLoading()
fetchData { [weak self] in
self?.delegate?.hideLoading()
}
}
// I have another function that uses this one. But it's not included in the sample
private func fetchData(then completion: @escaping (() -> Void)) {
service.start() { [weak self] (_, error) in
if error == nil {
if self?.shouldTrackScreen == false {
self?.shouldTrackScreen = true
self?.delegate?.trackScreen()
}
}
completion()
}
}所以当我想到handleViewDidLoad函数的测试用例时。我将有以下几点:
showLoading。hideLoading。hideLoading。service.start()。handleReloadData测试用例也是如此。通过这种方式,我将得到上述每个测试用例的副本。如果我有另一个使用fetchData函数的函数,我还必须重复第四个测试用例。
有办法克服这些重复吗?
用于澄清的样本测试用例
1- handleViewDidLoad试验
func testHandleViewDidLoadCallsShowLoading() {
// Given
stubService(forAction: actionType)
// When
sut.handleViewDidLoad()
// Then
verify(mockDelegate, times(1)).showLoading()
}
func testHandleViewDidLoadCallsHideLoadingWhenServiceSucceeds() {
// Given
stubService(forAction: actionType)
// When
sut.handleViewDidLoad()
// Then
verify(mockDelegate, times(1)).hideLoading()
}
func testHandleViewDidLoadCallsHideLoadingWhenServiceFails() {
// Given
stubService(forAction: actionType, error: VFAppError())
// When
sut.handleViewDidLoad()
// Then
verify(mockDelegate, times(1)).hideLoading()
}2- handleReloadData试验
func testHandleReloadDataCallsShowLoading() {
// Given
stubService(forAction: actionType)
// When
sut.handleReloadData()
// Then
verify(mockDelegate, times(1)).showLoading()
}
func testHandleReloadDataCallsHideLoadingWhenServiceSucceeds() {
// Given
stubService(forAction: actionType)
// When
sut.handleReloadData()
// Then
verify(mockDelegate, times(1)).hideLoading()
}
func testHandleReloadDataCallsHideLoadingWhenServiceFails() {
// Given
stubService(forAction: actionType, error: Error())
// When
sut.handleReloadData()
// Then
verify(mockDelegate, times(1)).hideLoading()
}在每个测试用例之前运行的setup方法中,我有
override func setUp() {
// Put setup code here. This method is called before the invocation of each test method in the class.
super.setUp()
sut = Presenter(viewController: mockDelegate, service: mockService)
stubDelegate()
}发布于 2020-09-28 22:51:38
如果有两个公共函数使用的私有函数,则会遇到测试用例副本。
不你不知道。
我知道人们说测试私人功能的方法是通过使用它的公共功能。这是正确的,但这仍然是错误的思维方式。
你不测试“私人功能”。您将测试单元公共接口后面的所有代码、抽象、被测试的系统(这可能是一个公共函数)。
要说“所有的代码”,最好的方法就是代码覆盖率。如果您正在测试的内容使用了一个私有函数,那么您的测试就会更好地使用它。不是因为这是个函数。因为这是你测试的一部分。
如果你担心你在练习相同的代码两次,停止它。测试甚至都不应该知道。除非这个私有函数减慢了系统的爬行速度,否则您只是在进行微优化。不要指望任何人会感谢你解决不了的问题。
模拟私有函数和模拟像Math.abs()这样的公共库调用一样有意义。只要它是及时的,确定性的,没有奇怪的依赖和副作用,就把它看作是公共功能的一部分。
测试不应该知道公共功能是如何工作的。只是它起作用了。这样,您就可以决定是否使用私有函数。考试没有意见。
发布于 2020-09-28 19:39:30
下面是一个非常简单的解决方案:
如果有几个测试用例验证相同条件或同一对象的不同入口函数的相同行为,则将重复的断言代码重构为一个公共函数。
在随后给出的例子中,被调用的sut的成员函数必须是提取函数的参数。我不知道Swift,但我想它有必要的功能工具,所以把它当作伪代码:
func testMySutFuncionCallsShowLoading( mySutFunction: ()->() ) {
// Given
stubService(forAction: actionType)
// When
mySutFunction()
// Then
verify(mockDelegate, times(1)).showLoading()
}
func testHandleReloadDataCallsShowLoading() {
testMySutFuncionCallsShowLoading ( ()-> sut.handleReloadData())
}
func testHandleViewDidLoadCallsShowLoading() {
testMySutFuncionCallsShowLoading ( ()-> sut.handleViewDidLoad())
}干法原理不仅适用于生产代码,而且可以(而且应该)应用于测试代码。
注意,所描述的问题与以下事实没有多大关系:loadData是一个私有函数,当loadData成为公共函数时,或者当loadData通过将其代码直接复制到调用方法而被消除时,它将保持不变。
https://softwareengineering.stackexchange.com/questions/416345
复制相似问题