扩展方法和 VS2008 中的单元测试
使用 .NET 3.5 创建一些有用的扩展方法,然后使用 VS2008 Professional 内置的单元测试功能来测试你的新方法。
目录
引言
本文将使用 Visual Studio 2008 Beta 2 Professional 版本提供的一些新功能。如果你还没有下载,请立即下载。我使用它已经近 3 个月了,并且从未后悔。我现在用它来处理所有 HTML 和 CSS 编辑,包括撰写本文。它不仅拥有大量新功能,还带来了性能提升,并且尽管它仍是 beta 版本,但我使用它期间从未遇到任何问题或崩溃。
VS2008 Pro 的一些新功能
- 多重目标 - 可针对不同的 .NET Framework 版本。
- 分屏所见即所得 - 可同时查看设计视图和源代码。
- JavaScript 智能感知和调试.
- 改进的 CSS 支持.
- 嵌套母版页.
- 单元测试.
一些新的 .NET 3.5 功能
我将不解释一些新功能是什么,而是让 Scott Guthrie 的博客文章来介绍。
扩展方法
最吸引我眼球的功能之一就是扩展方法。扩展方法“允许开发人员在不继承现有 CLR 类型或重新编译原始类型的情况下,为其公共契约添加新方法。”它们还使得 LINQ 等强大功能成为可能。我还意识到现在可以“添加”功能到现有的框架类中,例如 `System.String` 类。我一直有一个静态字符串实用工具类,我在所有项目和应用程序中都使用它。这是我多年来在使用 .NET 时构建和发展起来的utils类库的一部分。因此,这是使用 3.5 版本重写我的实用工具类库并利用(和学习)新功能的绝佳机会。我已经开始这么做了,并且正在撰写博客介绍我的进展。
第一个示例
下面代码中可以看到一个极其简单(且无用!)的扩展方法示例。
namespace Utils.MyExtensions
{
public static class JunkExtensions
{
public static string ToSomethingElse(this string input)
{
return input.PadLeft(10);
}
}
}
请注意,你的扩展方法必须定义在一个非泛型静态类中。现在,要使用扩展方法,请在你的代码中包含该命名空间。
using Utils.MyExtensions;
……然后你的新扩展方法就可以使用了,正如在智能感知中看到的那样。
何时不使用它们
我首先承认扩展方法可能既有用又强大,但何时才算足够呢?Scott Guthrie 在他的文章中说:“与任何可扩展性机制一样,我强烈建议一开始不要过度创建新的扩展方法。仅仅因为你有一个闪亮的新锤子,并不意味着世界上的一切突然都变成了钉子!”再好的话也不过如此。听 Scott 的——他最清楚。你不能将所有静态实用方法都转换为扩展方法。有什么意义呢?你真的想看到一个拥有数百种可用方法的字符串类,但你大部分时间只使用其中的 10% 吗?显然不是。
何时使用它们
你应该只转换你最常用、最可重用的静态方法。不要仅仅因为你能就创建扩展方法;而要因为你知道它能帮助你写出更智能的代码而创建它。我创建扩展方法,是认为它们能够改进和扩展框架,并且我认为它们也应该成为框架的一部分。当我发现自己问:“但为什么他们不将此方法包含在框架中?”时,一个新的扩展方法通常很快就会随之而来。
另外,创建一些仅仅是你的实用方法包装器的扩展方法。这样,实用代码和扩展方法代码就可以分开,开发人员可以选择使用扩展方法,也可以不使用。这可以用一个示例实用方法来轻松解释:
public static string CutEnd(string input, int length)
{
if (IsEmpty(input)) return input;
if (input.Length <= length) return string.Empty;
return input.Substring(0, input.Length - length);
}
这是我的扩展方法:
public static string CutEnd(this string input, int length)
{
return Utils.Strings.CutEnd(input, length);
}
这给了开发人员他们想要的自由,他们可以使用扩展方法或静态方法。此外,两种方法只需要进行一套测试。
奇怪的行为
现在,我曾认为创建一个检查 null 的扩展方法是相当没用的。我的想法是:“如果对象是 null,我怎么检查 null 呢?我不会收到 `NullReferenceException` 吗?”嗯,我测试了一下,结果是不会——你不会收到异常。这是扩展方法:
public static bool IsNullOrEmpty(this string input)
{
if (input == null) return true;
return input.Length == 0;
}
这是测试它的代码:
string str = null;
if (!str.IsNullOrEmpty())
{
Console.Write(str);
}
这段代码运行正常——没有任何问题!确实很奇怪,但同时又很有用。可以在 http://diditwith.net 阅读更多相关内容。
测试扩展方法
当开发任何将被反复重用的代码(包括扩展方法)时,为该代码编写测试就变得必不可少。这是为了确保代码既可靠又无 bug。在创建将在每个项目上重用且在其生命周期中可能多次更改的可重用框架时,测试就成为绝对必需!利用这些类型测试的唯一明智方法是编写单元测试。单元测试允许你维护一套可以在任何时候、反复运行的测试,以检查所有用例场景。因此,当你更改一个实用方法时,运行该方法的单元测试,以确保它仍然按预期工作。市面上有许多单元测试框架,包括 NUnit,它是一个用 C# 编写的开源框架。你也可以购买和/或下载 Visual Studio 的插件,以便在 IDE 中进行单元测试,但这已不再需要。VS2008 Pro 中现在内置了单元测试功能。太棒了!
VS2008 Professional 中的单元测试
只需点击几下鼠标,你就可以为你编写的代码创建单元测试。让我们为我们的扩展方法这样做。
- 点击“测试”菜单,然后选择“新建测试”。
- 选择“单元测试向导”选项,然后点击“确定”。
- 输入新测试项目的名称。
- 选择要测试的方法,然后点击“确定”。
就是这么简单!我们现在已经创建了一个名为 UtilsTests 的新项目,其中包含我们刚刚创建的扩展方法的所有测试。
现在你需要做的就是根据你的需求自定义这些测试。这是生成的测试代码:
/// <summary>
///A test for ToSomethingElse
///</summary>
[TestMethod()]
public void ToSomethingElseTest()
{
string input = string.Empty; // TODO: Initialize to an appropriate value
string expected = string.Empty; // TODO: Initialize to an appropriate value
string actual;
actual = JunkExtensions.ToSomethingElse(input);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
}
正如你所见,它会智能地查看方法的输入参数并为你生成测试。现在你只需要更改输入和预期输出,然后删除 `Assert.Inconclusive` 行,添加一些调整,就可以得到一个可用的单元测试。现在测试应该看起来是这样的:
[TestMethod()]
public void ToSomethingElseTest()
{
string input = "abc123";
string expected = " abc123";
string actual = input.ToSomethingElse();
Assert.AreEqual(expected, actual);
}
显然,单元测试的好坏取决于编写它的程序员。因此,请确保你的单元测试广泛。实际上,要比你通常写的更广泛,甚至要考虑到最简单的情况。事实上,在编写单元测试时要多疑。这样,你就能确保你的测试涵盖了所有角度。
现在通过点击“测试”>“运行”>“解决方案中的所有测试”来运行你的测试。
……并在 VS2008 中查看结果。
从截图中可以看出,并非所有测试都通过了。现在我们需要深入代码,找出原因。所以,就像你通常作为 VS 开发人员那样,在你的失败测试代码中设置一个断点。但这次,不要只运行你的测试,而是选择在调试模式下运行它们,方法是点击“测试”>“调试”>“解决方案中的所有测试”。
现在你可以单步执行代码,找出测试失败的原因。
结论
因此,我们已经演示了一个关于扩展方法是什么以及如何编写单元测试来测试它们的非常简单的例子。我希望这篇文章激发了你对 VS2008 中新功能的一些兴趣,因为它们极大地帮助我提高了编码效率。我使用 .NET Framework 3.5 编写的新实用工具项目每天都在使用单元测试功能。例如,我每天似乎都在更改或为我的字符串实用工具类添加功能,还有什么比运行一套单元测试更能让我了解和信任我的更改有效呢?
去看看我用 .NET 3.5 编写的字符串实用工具类,里面有一些方便的扩展方法。在那里你可以下载源代码,其中包括方法的完整单元测试。
历史
- 2007 年 11 月 4 日:提交版本 1。