我是单元测试的新手,我正在使用VS 2010单元测试框架。
我有一个从用户那里抓取一个整数的函数,然后根据用户输入执行不同的函数。我已经阅读了很多单元测试,但我没有找到任何能告诉我如何测试switch语句的每个分支的东西。到目前为止我得到了什么:
[TestMethod]
public void RunBankApplication_Case1()
{
using (var sw = new StringWriter())
{
using (var sr = new StringReader("1"))
{
Console.SetOut(sw);
Console.SetIn(sr);
BankManager newB = new BankManager();
newB.RunBankApplication();
var result = sw.ToString();
string expected = "Enter Account Number: ";
Assert.IsTrue(result.Contains(expected));
}
}
}
当调用案例1下的函数时,首先发生的是字符串“输入帐号:”被写入控制台。 但是,这根本不起作用。我没有正确地将输入传递给控制台吗? 谢谢你的帮助!
编辑:我的RunBankApplication()函数:
do
{
DisplayMenu();
option = GetMenuOption();
switch (option)
{
case 1:
if (!CreateAccount())
{
Console.WriteLine("WARNING: Could not create account!");
}
break;
case 2:
if (!DeleteAccount())
{
Console.WriteLine("WARNING: Could not delete account!");
}
break;
case 3:
if (!UpdateAccount())
{
Console.WriteLine("WARNING: Could not update account!");
}
break;
case 4: DisplayAccount();
break;
case 5: status = false;
break;
default: Console.WriteLine("ERROR: Invalid choice!");
break;
}
} while (status);
答案 0 :(得分:3)
我认为您的RunBankApplication
看起来与此相似:
public void RunBankApplication()
{
var input = Console.ReadLine();
switch (input)
{
case "1":
Console.WriteLine("Enter Account Number: ");
break;
case "2":
Console.WriteLine("Hello World!");
break;
default:
break;
}
}
要了解Console
上的固定依赖项,这会使您的方法不可测试,您应该在构造函数中注入此依赖项。
您需要一个定义依赖关系的接口:
public interface IConsoleService
{
string ReadLine();
void WriteLine(string message);
}
您可以为它创建默认实现:
public class ConsoleService : IConsoleService
{
public string ReadLine()
{
return Console.ReadLine();
}
public void WriteLine(string message)
{
Console.WriteLine(message);
}
}
然后,在BankManager
类中注入此实现,并在类中使用它:
public class BankManager
{
private IConsoleService _consoleService;
public BankManager(IConsoleService consoleService)
{
_consoleService = consoleService;
}
public void RunBankApplication()
{
var input = _consoleService.ReadLine();
switch (input)
{
case "1":
_consoleService.WriteLine("Enter Account Number: ");
break;
case "2":
_consoleService.WriteLine("Hello World!");
break;
default:
break;
}
}
}
现在,您可以在测试中模拟此依赖项。 Moq是这样一个模拟库的好选择:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void GetMessage_Input1_ReturnEnterAccountNumberMessage()
{
var consoleService = new Mock<IConsoleService>();
consoleService.Setup(c => c.ReadLine()).Returns("1");
var bankManager = new BankManager(consoleService.Object);
bankManager.RunBankApplication();
consoleService.Verify(c => c.WriteLine("Enter Account Number: "), Times.Once());
}
[TestMethod]
public void GetMessage_Input2_ReturnHelloWorldMessage()
{
var consoleService = new Mock<IConsoleService>();
consoleService.Setup(c => c.ReadLine()).Returns("2");
var bankManager = new BankManager(consoleService.Object);
bankManager.RunBankApplication();
consoleService.Verify(c => c.WriteLine("Hello World!"), Times.Once());
}
}
当然,这对于这样一个简单的例子来说太过分了,但这种方法在大型项目中非常有用。然后,您可以使用IoC container在应用程序中自动注入依赖项。
答案 1 :(得分:2)
不应该有用户输入自动测试。您的测试需要提供参数,如果您依赖外部资源(WCF服务,数据库,文件系统,用户输入等等),那么您需要模拟它们。这就是像Moq这样的测试框架为您做的事情。
如果你想测试switch语句的每个case,那么你需要对每个case进行测试。
顺便说一句,您无法使用控制台,因为您的单元测试可能位于类库中,而不是控制台应用程序。
答案 2 :(得分:1)
这不是正确的方法。您不应该在单元测试中与控制台通信。只需提取适用于输入参数的函数并测试此函数。
像这样: public string GetMessage(string input)
{
var result = string.Empty;
switch (input)
{
case "1":
result = "Enter Account Number: ";
break;
case "2":
result = "Hello World!";
break;
default:
break;
}
return result;
}
...
在YourExtractedClass的Test类中
[Test]
public void GetMessage_Input1_ReturnEnterAccountNumberMessage()
{
var result = GetMessage("1");
var expected = "Enter Account Number: ";
Assert.That(result == expected);
}
[Test]
public void GetMessage_Input2_ReturnHelloWorldMessage()
{
var result = GetMessage("1");
var expected = "Hello World!";
Assert.That(result == expected);
}
还有一件事:最好将字符串(“输入帐号”等)移动到一个地方(例如某些常量类)。不要重复自己!
阅读关于单元测试的好书:
The Art of Unit Testing: With Examples in .Net