C#单元测试解析器
我需要编写一个解析器。有很多我想测试的输入格式,输出非常复杂。我应该如何用相似的测试来测试不同的输入和输出?C#单元测试解析器
例如
public class Person
{
public string Name;
public int Age;
public string Comment;
}
public interface IParser
{
Person Parse(string input);
}
public class Parser : IParser
{
public Person Parse(string input)
{
var fields = input.Split(',');
var p = new Person
{
Name = fields[0],
Age = int.Parse(fields[1])
};
p.Comment = fields.Length == 3 ? fields[2] : "";
return p;
}
}
我写这些测试...
public class ParserTests
{
protected string _input;
protected Person _expected;
private IParser _parser = new Parser();
private Person _actual { get { return _parser.Parse(_input); } }
[TestMethod]
public void Parse_Name()
{
Assert.AreEqual(_expected.Name, _actual.Name);
}
[TestMethod]
public void Parse_Age()
{
Assert.AreEqual(_expected.Age, _actual.Age);
}
[TestMethod]
public void Parse_Comment()
{
Assert.AreEqual(_expected.Comment, _actual.Comment);
}
}
[TestClass]
public class ParserTestsWithoutComment : ParserTests
{
public ParserTestsWithoutComment()
{
_input = "John,29";
_expected = new Person { Name = "John", Age = 29, Comment = "" };
}
}
[TestClass]
public class ParserTestsWithComment : ParserTests
{
public ParserTestsWithComment()
{
_input = "Brian,99,test";
_expected = new Person { Name = "Brian", Age = 99, Comment = "test" };
}
}
我是新来的单元测试,我不知道如何下手更复杂的东西。我真正的输入文件是比较复杂的滋味
PokerStars Hand #98451585362: Hold'em No Limit ($5/$10 USD) - 2013/05/12 9:25:04 CET [2013/05/12 3:25:04 ET]
Table 'Soyuz-Apollo II' 6-max Seat #4 is the button
Seat 1: Codrus426 ($1812.52 in chips)
Seat 2: JMBigJoe ($2299.10 in chips)
Seat 3: xinxin1 ($903.94 in chips)
Seat 4: moshmachine ($1107 in chips)
Seat 5: TopKat5757 ($1147 in chips)
Seat 6: LukaschenkoA ($1274.96 in chips)
TopKat5757: posts small blind $5
LukaschenkoA: posts big blind $10
*** HOLE CARDS ***
Codrus426: calls $10
JMBigJoe: raises $25 to $35
xinxin1: folds
moshmachine: folds
TopKat5757: folds
LukaschenkoA: folds
Codrus426: calls $25
*** FLOP *** [2h 3s 6h]
Codrus426: checks
JMBigJoe: bets $41
Codrus426: calls $41
*** TURN *** [2h 3s 6h] [2d]
Codrus426: bets $40
JMBigJoe: calls $40
*** RIVER *** [2h 3s 6h 2d] [Qh]
Codrus426: checks
JMBigJoe: checks
*** SHOW DOWN ***
Codrus426: shows [9d Ah] (a pair of Deuces)
JMBigJoe: mucks hand
Codrus426 collected $244 from pot
*** SUMMARY ***
Total pot $247 | Rake $3
Board [2h 3s 6h 2d Qh]
Seat 1: Codrus426 showed [9d Ah] and won ($244) with a pair of Deuces
Seat 2: JMBigJoe mucked
Seat 3: xinxin1 folded before Flop (didn't bet)
Seat 4: moshmachine (button) folded before Flop (didn't bet)
Seat 5: TopKat5757 (small blind) folded before Flop
Seat 6: LukaschenkoA (big blind) folded before Flop
而且我希望它解析为Hand
类我的工作......
public class Hand
{
public long ID;
public string Stakes;
public DateTime Date;
public IDictionary<Street, decimal> Pots;
public decimal FinalPot;
public decimal Rake;
public Player Hero;
public IDictionary<Player, PlayerInfo> Players;
public IList<Card> Board;
public IList<Decision> Actions;
public Hand()
{
this.Players = new Dictionary<Player, PlayerInfo>();
this.Board = new List<Card>();
this.Actions = new List<Decision>();
this.Pots = new Dictionary<Street, decimal>();
}
}
public class PlayerInfo
{
public Player Player;
public decimal Stack;
public decimal Summary;
public Position Position;
public Card Holecards;
}
我觉得你的结构是相当不错的,记住TMTOWTDI。
但是,确保明确测试Parse
为空,空(即零长度)和空白字符串。更复杂/预期路径的情况当然是测试的关键,但这样的简单情况也很重要。
此外,您使用的是结构很可能被折叠成ParserTests
一个共同%MethodUnderTest%_With%Condition(s)%_Expect%ExpectedResult%
测试用例命名约定和可选的Test Data Builder模式再拍类负责建立像你这样的测试数据,现在正在做你的ParserTests
子
由于您将全局变量与继承结合在一起,您的解决方案正在运行但难以理解。
如果您使用的是NUnit 2.5或更高版本,则可以使用Parameterized Tests with TestCaseAttribute。
[TestCase("John,29","John",29,"")]
[TestCase(",13","",13,"")]
public void ParserTest(Sting stringToParse, String expextedName, int expectedAge, String expectedComment)
{
IParser _parser = new Parser();
Person _actual = _parser.Parse(stringToParse);
Assert.AreEqual(expextedName, _actual.Name, stringToParse + " failed on Name");
Assert.AreEqual(expextedAge, _actual.Age, stringToParse + " failed on Age");
Assert.AreEqual(expextedComment, _actual.Comment, stringToParse + " failed on Comment");
}
我觉得这样更容易理解。
如果你需要和你在一起有模拟它的描述下在how-to-rowtest-with-mstest
@Pankracy:k3b在参数化单元测试中对此进行了一些清理。这个想法让我想起了现在的结构可以被折叠成“ParserTests”。我已经完成了这个晚上,但会尝试尽快跟上代码,以更好地解释我的意思。 – J0e3gan 2013-05-12 07:22:32
对不起,我将更新我的第一篇文章,我想解析的真实数据。 – Pankracy1999 2013-05-12 07:27:54
如果您使用NUnit,你可以使用测试用例这个MSTEST,这是非常干净的海事组织 – 2013-05-12 06:30:36
我同意 - 很干净。我无法同意@JohanLarsson的观点,尽管NUnit现在主要用于单元测试,但NUnit会大幅改善任何事情。 MSTest也适合你在做什么。 – J0e3gan 2013-05-12 06:35:13