这是TDD的正确方法吗?
本文关键字:方法 TDD 这是 | 更新日期: 2023-09-27 18:30:52
此处为TDD的新功能。只是需要一些关于我是否以正确的方式解决这个问题的指导。我希望使用 TDD 将罗马数字字符串转换为整数。我有 2 个担忧(另外,如果有人可以指出其他问题,请这样做):
- 感觉我可能写了太多类似的测试,比如I_returns_1、II_returns_2等。我应该结合其中的一些吗测试?或者数到 20,我真的应该有 20 次测试吗?
-
我重构得也够多了吗?否则,有什么建议吗?
private static readonly Dictionary<string, int> Specials = new Dictionary<string, int>() { {"IV", 4}, {"IX", 9} }; public static int? Convert(string input) { if (input == null) return null; var processed = input; var counter = 0; foreach (var special in Specials) { if (!processed.Contains(special.Key)) continue; processed = processed.Replace(special.Key, ""); counter = counter + special.Value; } for (int i = 0; i < processed.Length; i++) { if (processed[i] == 'X') counter = counter + 10; if (processed[i] == 'V') counter = counter + 5; if (processed[i] == 'I') counter++; } return counter; }
这是上面创建的测试...
[TestClass]
public class UnitTest1
{
[TestMethod]
public void Check_Null_returns_Exception()
{
var result = Program.Convert(null);
Assert.AreEqual(result,null);
}
[TestMethod]
public void I_returns_1()
{
var result = Program.Convert("I");
Assert.AreEqual(result, 1);
}
[TestMethod]
public void II_returns_2()
{
var result = Program.Convert("II");
Assert.AreEqual(result, 2);
}
[TestMethod]
public void Multiple_I_returns_number()
{
var result = Program.Convert("III");
Assert.AreEqual(result, 3);
}
[TestMethod]
public void IV_returns_4()
{
var result = Program.Convert("IV");
Assert.AreEqual(result, 4);
}
[TestMethod]
public void V_returns_5()
{
var result = Program.Convert("V");
Assert.AreEqual(result, 5);
}
[TestMethod]
public void VI_returns_6()
{
var result = Program.Convert("VI");
Assert.AreEqual(result, 6);
}
[TestMethod]
public void VII_returns_7()
{
var result = Program.Convert("VII");
Assert.AreEqual(7,result);
}
[TestMethod]
public void VIII_returns_8()
{
var result = Program.Convert("VIII");
Assert.AreEqual(8,result);
}
[TestMethod]
public void IX_returns_9()
{
var result = Program.Convert("IX");
Assert.AreEqual(9, result);
}
[TestMethod]
public void X_returns_10()
{
var result = Program.Convert("X");
Assert.AreEqual(10, result);
}
[TestMethod]
public void Test_XI_to_XIII()
{
Assert.AreEqual(11, Program.Convert("XI"));
Assert.AreEqual(12, Program.Convert("XII"));
Assert.AreEqual(13, Program.Convert("XIII"));
}
[TestMethod]
public void XIV_returns_14()
{
var result = Program.Convert("XIV");
Assert.AreEqual(14, result);
}
[TestMethod]
public void XV_returns_15()
{
var result = Program.Convert("XV");
Assert.AreEqual(15, result);
}
[TestMethod]
public void XVI_returns_16()
{
var result = Program.Convert("XVI");
Assert.AreEqual(16, result);
}
[TestMethod]
public void XVI_returns_17()
{
var result = Program.Convert("XVII");
Assert.AreEqual(17, result);
}
[TestMethod]
public void XVI_returns_18()
{
var result = Program.Convert("XVIII");
Assert.AreEqual(18, result);
}
[TestMethod]
public void XIX_returns_19()
{
var result = Program.Convert("XIX");
Assert.AreEqual(19, result);
}
[TestMethod]
public void XX_returns_20()
{
var result = Program.Convert("XX");
Assert.AreEqual(20, result);
}
}
首先,单元测试名称应该是有意义的,而不仅仅是描述代码。
II_returns_2
没有解释测试试图保证什么。 II_should_be_interpreted_as_the_roman_representation_of_2
更好地解释了业务规则。
这很重要,因为当你从知道和阅读测试名称一年后回到代码II_returns_2
你不会知道你为什么要写这个测试。(好吧,在这个微不足道的例子中,你可能会,但不是在典型的应用程序中)
接下来是方法名称将相似,但由于代码路径不同(应用程序根据罗马数字执行不同的分支),您需要进行不同的测试。
幸运的是,几个不同的单元测试库支持使用属性来定义一组不同的测试值。
这是来自xunit的示例。
[Theory]
[InlineData("I", 1)]
[InlineData("II", "2")]
[InlineData("III", "3")]
public void test(string roman, int number)
{
var actual = Program.Convert(roman);
Assert.AreEqual(actual, number);
}
重复从来都不是好的(DRY),所以类似的测试应该用一个测试来表示。我不熟悉Microsoft的单元测试框架,但在 NUnit 中,您可以使用 TestCase 属性并编写如下内容:
[TestFixture]
public class RomanNumeralConverter_Tests
{
[TestCase("I", 1)]
[TestCase("II", 2)]
[TestCase("III", 3)]
[TestCase("IV", 4)]
[TestCase("V", 5)]
[TestCase("VI", 6)]
// etc...
public void Convert_returns_decimal_representation(string roman, int expectedDecimal)
{
var result = Program.Convert(roman);
Assert.AreEqual(expectedDecimal, result);
}
}