测试驱动开发:构建CUSIP验证器

在本文中,将探讨如何使用Microsoft.VisualStudio.TestTools.UnitTesting在VB.NET中实现测试驱动开发(TDD)。测试驱动开发是一种软件开发方法,它要求开发者首先编写测试用例,然后编写能够通过这些测试用例的代码。这种方法有助于确保代码的质量和可维护性。将通过构建一个CUSIP验证器的例子来演示这个过程。

创建框架代码

首先,需要创建一个空的类框架,这个类将实现CUSIP验证的逻辑。以下是VB.NET的代码示例:

Public MustInherit Class SecurityIdentifier Private _securityIdentifier As String Public ReadOnly Property Identifier As String Get Return _securityIdentifier End Get End Property Public Sub New(ByVal securityIdentifier As String) _securityIdentifier = securityIdentifier End Sub End Class Public Class CusipIdentifier Inherits SecurityIdentifier Implements ISecurityIdentifierValidation Public Function IsValid() As Boolean Implements ISecurityIdentifierValidation.IsValid Return False End Function Public Sub New(ByVal cusipSecurityIdentifier As String) MyBase.New(cusipSecurityIdentifier) End Sub End Class

在这个阶段,验证逻辑尚未实现,因此始终返回False。

创建测试

接下来,需要创建一个测试套件,用于测试CUSIP验证器。首先,创建一个新的类,并使用TestClass属性进行装饰,以告知测试运行器该类包含测试用例。

Imports System.Text Imports Microsoft.VisualStudio.TestTools.UnitTesting <TestClass()> Public Class CusipUnitTest End Class

然后,添加一些测试用例来检查类构造函数是否能够正确处理不同的cusipSecurityIdentifier值:

<TestMethod()> <TestCategory("CUSIP")> Public Sub CusipEmptyCreateTestMethod() Dim cusipTest As New CusipIdentifier(String.Empty) Assert.IsNotNull(cusipTest) End Sub <TestMethod()> <TestCategory("CUSIP")> Public Sub CusipBlankCreateTestMethod() Dim cusipTest As New CusipIdentifier("") Assert.IsNotNull(cusipTest) End Sub <TestMethod()> <TestCategory("CUSIP")> Public Sub CusipNothingCreateTestMethod() Dim cusipTest As New CusipIdentifier(Nothing) Assert.IsNotNull(cusipTest) End Sub

每个测试用例都以一个Assert语句结束。如果该语句的结果为True,则测试通过;如果结果为False或发生任何异常,则测试失败。

添加正向测试

接下来,添加一些正向测试,这些测试用于检查代码在某些预期有效的值上是否能够正常工作。例如,可以选取一组已知有效的公司CUSIP标识符进行测试:

<TestMethod()> <TestCategory("CUSIP")> Public Sub CusipAgilentValidTestMethod() Dim cusipTest As New CusipIdentifier("00846U101") Dim expected As Boolean = True Dim actual As Boolean = False actual = cusipTest.IsValid() Assert.AreEqual(expected, actual) End Sub

注意,总是将"expected"变量初始化为与"actual"变量不同的值。这样做是为了确保只有当测试改变了变量值时,测试才能通过。为了获得良好的测试覆盖率,应该将大约30个正确的值编码到测试中。

添加负向测试

现在,添加一些负向测试,这些测试用于检查代码是否能够排除预期无效的情况。为了创建负向测试,可以取一个有效的CUSIP,并更改其任何一个构成数字。同样,确保实际变量在测试中发生变化:

<TestMethod()> <TestCategory("CUSIP")> Public Sub CusipSprintInValidTestMethod_9() Dim cusipTest As New CusipIdentifier("852061109") Dim expected As Boolean = False Dim actual As Boolean = True actual = cusipTest.IsValid() Assert.AreEqual(expected, actual) End Sub

接下来,即使还没有编写实现验证逻辑的代码,也需要运行测试。这是测试驱动开发的关键区别:首先编写测试用例,然后运行它们以检查它们是否失败。在上面的例子中,只有正向测试会失败,因为验证始终返回False。如果在编写任何业务逻辑代码之前所有测试都通过,那么需要检查测试代码并添加更多的测试。

填充框架代码

最后,编写业务逻辑代码,一旦编写完成,就立即运行所有测试。以下是最终工作的CUSIP验证器的代码:

Public Class CusipIdentifier Inherits SecurityIdentifier Implements ISecurityIdentifierValidation Public Function IsValid() As Boolean Implements ISecurityIdentifierValidation.IsValid If String.IsNullOrWhiteSpace(MyBase.Identifier) Then Return False End If If MyBase.Identifier.Length = 9 Then Dim checkDigitExpected As Integer = _ GetStringValue(MyBase.Identifier.Substring(0, 8)) Dim checkDigitActual As Integer If Integer.TryParse(MyBase.Identifier.Substring(8), checkDigitActual) Then Return (checkDigitActual = checkDigitExpected) Else Return False End If Else Return False End If End Function Public Sub New(ByVal cusipSecurityIdentifier As String) MyBase.New(cusipSecurityIdentifier) End Sub Private Function GetLetterValue(ByVal letter As Char) As Integer Select Case letter Case "0": Return 0 Case "1": Return 1 Case "2": Return 2 ... Case "Z": Return 35 Case "*": Return 36 Case "@": Return 37 Case "#": Return 38 Case Else: Throw New ArgumentOutOfRangeException("letter", "Specified letter is not part of the CUSIP allowed letter list") End Select End Function Private Function GetStringValue(ByVal cusipString As String) As Integer If cusipString.Length < 8 Then Throw New ArgumentOutOfRangeException("cusipString", "CUSIP is too short") Else Dim sum As Integer = 0 For letterPos As Integer = 0 To 7 Step 1 Dim v As Integer If ((letterPos Mod 2) = 1) Then v = 2 * GetLetterValue(cusipString.Chars(letterPos)) Else v = GetLetterValue(cusipString.Chars(letterPos)) End If sum = sum + ((v \ 10) + (v Mod 10)) Next Return (10 - (sum Mod 10)) Mod 10 End If End Function End Class
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485