我正在编写一个解析器,为每个命令生成32位操作码。例如,对于以下语句:
set lcl_var = 2
我的解析器生成以下操作码:
// load immdshort 2 (loads the value 2)
0x10000010
// strlocal lclvar (lcl_var is converted to an index to identify the var)
0x01000002
请注意lcl_var
可以是任何内容,即可以给出任何变量。如何为此编写单元测试用例?我们可以避免对值进行硬编码吗?有没有办法让它变得通用?
答案 0 :(得分:2)
这取决于您如何构建解析器。单元测试测试单个UNIT。
因此,如果要将整个解析器作为一个单元进行测试,可以给它一个命令列表并验证它是否产生正确的操作码(您在编写测试时手动检查)。您可以为每个命令编写测试,并测试正常使用情况,边缘情况使用情况,以及超出边缘情况的使用情况。例如,测试:
设置lcl_var = 2
结果:
0x10000010 0x01000002
0,-1,MAX_INT-1,MAX_INT + 1,...
相同您知道这些值的正确结果。同样适用于不同的变量。
答案 1 :(得分:1)
int[] opcodes = Parser.GetOpcodes("set lcl_var = 2");
Assert.AreEqual(2, opcodes.Length);
Assert.AreEqual(0x10000010, opcodes[0]);
Assert.AreEqual(0x01000002, opcodes[1]);
答案 2 :(得分:1)
如果您的问题是“如何在不为每个输入 - 输出组合编写一个xUnit测试的情况下,使用不同的输入和期望值运行相同的测试?”
然后答案就是使用类似RowTest NUnit扩展名的东西。我最近在我的博客上写了quick bootup post。 这方面的一个例子是
[TestFixture]
public class TestExpression
{
[RowTest]
[Row(" 2 + 3 ", "2 3 +")]
[Row(" 2 + (30 + 50 ) ", "2 30 50 + +")]
[Row(" ( (10+20) + 30 ) * 20-8/4 ", "10 20 + 30 + 20 * 8 4 / -")]
[Row("0-12000-(16*4)-20", "0 12000 - 16 4 * - 20 -")]
public void TestConvertInfixToPostfix(string sInfixExpr, string sExpectedPostfixExpr)
{
Expression converter = new Expression();
List<object> postfixExpr = converter.ConvertInfixToPostfix(sInfixExpr);
StringBuilder sb = new StringBuilder();
foreach(object term in postfixExpr)
{
sb.AppendFormat("{0} ", term.ToString());
}
Assert.AreEqual(sExpectedPostfixExpr, sb.ToString().Trim());
}
答案 3 :(得分:0)
你没有指定你正在编写解析器的语言,所以为了论证你将使用面向对象的语言。
如果是这种情况,那么依赖注入可以帮助你在这里。如果发出的操作码的目的地是类的实例(例如File),请尝试为您的发射器类提供一个构造函数,该构造函数将该类型的对象用作发出代码的目标。然后,从单元测试中,您可以传入一个模拟对象,该对象是目标类的子类的实例,捕获特定语句的发出操作码,并断言它们是正确的。
如果您的目标类不易扩展,您可能希望创建一个基于它的接口,目标类和模拟类都可以实现。
答案 4 :(得分:0)
据我了解,您首先要为您的特定示例编写一个测试,即解析器的输入是:
set lcl_var = 2
,输出为:
0x10000010 // load immdshort 2
0x01000002 // strlocal lclvar
当您实现了生产代码以通过该测试并重构它时,如果您不满意它可以处理任何局部变量,使用不同的局部变量编写另一个测试并查看它是否通过。例如带输入的新测试:
set lcl_var2 = 2
编写新测试以期望您想要的不同输出。继续这样做,直到您对您的生产代码足够强大感到满意为止。
答案 5 :(得分:0)
目前尚不清楚您是否正在寻找用于测试的方法或特定技术。
就方法论而言,您可能不希望进行大量的单元测试。也许更好的方法是用域特定语言编写一些程序,然后执行操作码以产生结果。然后测试程序将检查此结果。这样你可以运用一堆代码,但最后只检查一个结果。从简单的问题开始,清除明显的错误,转移到更难的错误。而不是每次都检查生成的操作码。
另一种方法是使用特定于域的语言自动生成程序以及预期的操作码。这可以非常简单,比如编写一个生成一组程序的perl脚本,如:
设置lcl_var = 2
设置lcl_var = 3
一旦您拥有一套具有正确输出的语言测试程序,您就可以反过来生成检查每个操作码的单元测试。由于您已经拥有了操作码,因此需要检查解析器的输出是否正确;审查其代码。
虽然我没有使用cppunit,但我使用的内部工具非常像cppunit。使用cppunit很容易实现单元测试。
答案 6 :(得分:0)
你想测试什么?您想知道是否创建了正确的“存储”指令吗?是否拾取了正确的变量?下定决心你想知道的,测试将是显而易见的。只要你不知道自己想要达到什么目的,就不会知道如何测试未知数。
与此同时,只需编写一个简单的测试。明天或晚些时候,你会再次来到这个地方,因为事情已经破裂。那时,您将更多地了解您想要做什么,并且设计测试可能更简单。
今天,不要试图成为明天的人。