c# - 使用和不使用私有(private)访问器的单元测试

标签 c# unit-testing

使用私有(private)访问器测试一段代码有什么缺点吗?

我正在权衡仅使用私有(private)访问器来测试我的 GUI 的选项,而不是公开公开的方法/属性。

这将允许我需要一些 GUI 测试,我只是想确保它们在使用私有(private)访问器的行为方式时没有任何隐藏的“陷阱”。

最佳答案

回顾一下,您的既定目标是:

I'm weighing the option of using a private accessor only to test my GUI... This will allow some GUI testing i need...

简而言之,是的,存在陷阱。您正在测试的代码仍然与用户界面紧密耦合。

在评论中,您将您的目标/问题阐明为:

What about in the case if i want to test, Drag/drop. Custom Controls, Overriden events?

我只能说欢迎加入。近半个世纪以来,软件行业一直在为此苦苦挣扎。事实是,测试 UI 很困难,真的很难。是的,您可以使用一段与 UI 元素紧密耦合的代码并尝试自动化它;然而,你将竭尽全力对抗错误的假设。

可测试 UI 的“技巧”不是让你的 UI 可测试,而是从 UI 中删除你想要测试的代码。因此,N 层应用程序开发和表示设计模式(如 MVC、MVVM 等)得到了广泛接受。

请参阅以下内容:

许多这些设计模式背后的主要目标或驱动力是消除行为和表示之间的紧密耦合。这使您能够在没有用户界面的情况下测试拖放等行为。我的建议是检查模式,选择您喜欢的模式,然后在编写单元测试时开始重构代码。

编写用于测试的 UI 的另一种方法是删除每个 if、else、for、while、switch 或其他 control statement从您的用户界面代码。由此产生的 UI“外壳”应该能够很好地适应变化。使用依赖反射的数据绑定(bind)之类的东西时要小心(这通常是可接受的做法)。这样做的主要缺点是编译器无法告诉您成员不再存在。

已更新

@timmy 你写道:

... for example if i want to test mouse click behavior...

那么鼠标单击行为不能移动到 Controller 而不是嵌入到表单中呢?我猜想“关闭”按钮可能有问题,但除此之外,为什么不将逻辑移至另一个可以测试的类呢?

顺便说一句,您不必只选择一种模式 MVC、MVVM 等,它们是“指南”或“建议”而不是硬性规则,所以不要对此感到可笑。只需尝试使逻辑与 UI 分离并可独立测试。例如,也许您的“Click”事件更适合简单的命令类?使用命令模式很简单,新建一个对象并执行它。考虑以下文件夹复制表单的示例代码:

private void OnCopyClick(object sender, EventArgs args)
{
    var cmd = new MyCopyCommand(this.FolderPath, this.txtTargetFolderPath.Text);
    new ErrorHandler(this).Perform(cmd);
}

这工作得很好,除了提供命令之外,它没有“真正的”逻辑,并且没有条件代码路径。请注意,我们甚至不直接调用该命令,而是将其推迟给能够正确处理错误的人。通常这个“ErrorHandler”会提供给表单而不是直接构造,但你明白了。

由此我们应该能够轻松验证 MyCopyCommand 的正确行为。最后你应该在 UI 中得到一堆“平面函数”,即。没有嵌套或花括号的函数。当然,这是一条经验法则,不要走得太极端,以免影响你的工作效率。

我知道这可能看起来工作量很大,但说实话,当您已经在编写一组测试时,这并不是什么工作。您可以提高工作效率并编写可靠的代码。你只需要知道什么时候作弊,什么时候不作弊。这是随着经验而来的,在 20 年之后,我编写了 10 个 NUnit,但我仍然偶尔会失败。当由于您没有这样做而出现问题时,首先从 UI 中提取逻辑,然后编写单元测试来证明它已损坏,然后修复它。

关于c# - 使用和不使用私有(private)访问器的单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13770666/

相关文章:

c++ - 微软 Visual Studio : How to keep the console open without manually reading input?

C 测试 - Unity 和 CMake 的 undefined reference

c# - 为什么 1 000 000 不等于 1000000.toString ("N", new CultureInfo ("fr-FR"))

c# - 异步调用永远不会在 Asp.Net MVC 中返回

ios - @testable import moduleName 不导入所有内容

c# - 数据绑定(bind)后如何将图像设置为数据 GridView 单元格?

c# - 被阻塞的 Windows 消息循环的调试思路

javascript - 如何在 Internet Explorer 中触发 script.onerror?

c# - T-SQL 可以存储 ulong 的吗?

c# - 对 PInvoke 函数 [函数名称] 的调用使堆栈不平衡