首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过公共接口测试私有功能的单元

通过公共接口测试私有功能的单元
EN

Software Engineering用户
提问于 2020-09-28 17:44:39
回答 2查看 496关注 0票数 1

我对单元测试很陌生,我一直在为测试私有功能的正确方法而奋斗。我已经做了我的研究,并将通过公共接口进行测试。

我的问题是,如果我有一个由两个公共函数使用的私有函数,我会遇到测试用例副本,我不知道如何克服这些问题。在所面临的情况下,将私有函数提取到另一个类似乎不合适,因为该函数仅足以使类使用它。

示例:

代码语言:javascript
复制
// 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函数的测试用例时。我将有以下几点:

  1. 检查是否调用了showLoading
  2. 检查在服务成功的情况下是否调用了hideLoading
  3. 检查在服务失败时是否调用了hideLoading
  4. 检查是否调用了service.start()

handleReloadData测试用例也是如此。通过这种方式,我将得到上述每个测试用例的副本。如果我有另一个使用fetchData函数的函数,我还必须重复第四个测试用例。

有办法克服这些重复吗?

编辑

用于澄清的样本测试用例

1- handleViewDidLoad试验

代码语言:javascript
复制
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试验

代码语言:javascript
复制
  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方法中,我有

代码语言:javascript
复制
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()
}
EN

回答 2

Software Engineering用户

发布于 2020-09-28 22:51:38

如果有两个公共函数使用的私有函数,则会遇到测试用例副本。

不你不知道。

我知道人们说测试私人功能的方法是通过使用它的公共功能。这是正确的,但这仍然是错误的思维方式。

你不测试“私人功能”。您将测试单元公共接口后面的所有代码、抽象、被测试的系统(这可能是一个公共函数)。

要说“所有的代码”,最好的方法就是代码覆盖率。如果您正在测试的内容使用了一个私有函数,那么您的测试就会更好地使用它。不是因为这是个函数。因为这是你测试的一部分。

如果你担心你在练习相同的代码两次,停止它。测试甚至都不应该知道。除非这个私有函数减慢了系统的爬行速度,否则您只是在进行微优化。不要指望任何人会感谢你解决不了的问题。

模拟私有函数和模拟像Math.abs()这样的公共库调用一样有意义。只要它是及时的,确定性的,没有奇怪的依赖和副作用,就把它看作是公共功能的一部分。

测试不应该知道公共功能是如何工作的。只是它起作用了。这样,您就可以决定是否使用私有函数。考试没有意见。

票数 7
EN

Software Engineering用户

发布于 2020-09-28 19:39:30

下面是一个非常简单的解决方案:

如果有几个测试用例验证相同条件或同一对象的不同入口函数的相同行为,则将重复的断言代码重构为一个公共函数。

在随后给出的例子中,被调用的sut的成员函数必须是提取函数的参数。我不知道Swift,但我想它有必要的功能工具,所以把它当作伪代码:

代码语言:javascript
复制
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通过将其代码直接复制到调用方法而被消除时,它将保持不变。

票数 4
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/416345

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档