我有一个程序使用控制台作为C#.NET中的GUI来解析来自用户的命令。它有不同的命令 - 其中一些必须是完全匹配,如"外观","库存"或"帮助"。其他人只需要包含部分单词或短语 - 任何带有" north"或"东"将开始向世界发展这一方向。
例如:
if(command == "help")
{ << Console.Writeline code to print the help >> }
else if (command.Contains == "inv")
{ << code using Console.Writeline to print the inventory >> )
else if (command.Contains("north"))
{ << code to move north, then print location info with Console.Writeline >>)
<< etc. >>
由于它是一个控制台应用程序,因此许多操作代码将作为输出写入控制台。我试图弄清楚如何对它进行单元测试,而我的(不可否认的是初学者)认为我应该删除对控制台的依赖并使用依赖注入来传递控制台(或者可能是通用接口到文本流或类似的东西?)到这个解析代码,以便我可以伪造控制台,但我不知道该怎么做。
依赖注入是否是在这里继续进行的正确方法 - 如果是,那么实现它的正确途径是什么?
答案 0 :(得分:2)
考虑testing pyramid你应该:
从使用脚本语言进行测试的集成测试盒测试开始,那些很少,应该是探索性的,或涉及涉及标准输入/输出的极端情况。
$process = New-Object System.Diagnostics.Process
$process.StartInfo.FileName = ".\mud.exe"
$process.StartInfo.UseShellExecute = $false
$process.StartInfo.RedirectStandardOutput = $true
$process.StartInfo.RedirectStandardInput = $true
if ( $process.Start() ) {
# input
$process.StandardInput.WriteLine("help");
$process.StandardInput.WriteLine();
# output check
$output = $process.StandardOutput.ReadToEnd()
if ( $output ) {
if ( $output.Contains("this is a help") ) {
Write "pass"
}
else {
Write-Error $output
}
}
$process.WaitForExit()
}
[Flags]
enum Commands
{
Help = 1,
Inv = 2,
North = 4
}
var p = new FluentCommandLineParser();
p.Setup<Commands>("c")
.Callback(c => command= c);
注入并输出您的输出,这样您就可以进行大量测试而无需太多模拟。
这意味着所有控制台编写都将由一个模块处理,您可以通过测试套件轻松伪造。
IConsoleBuilder { // actual implementation write to console
RegisterCommand(string command, Func<string[], string> action);
}
InventoryConsoleBuilder : ConsoleBuilderClient {
InventoryConsoleBuilder(IConsoleWriter writer){ _writer = writer; }
public override void Show(IInventory inventory) {
writer.RegisterCommand(inventoryComposed) ;
}
}
答案 1 :(得分:1)
由于它是一个控制台应用程序,因此许多操作代码将作为输出写入控制台。我正试图弄清楚如何对此进行单元测试
一种方法是使用 TraceListener 并将所有内容记录到文件而不是控制台。通常,我们使用TextWriterTraceListener
将Trace
和Debug
输出记录到文件中。
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[TestClass]
public class AssemblyInitUnitTest
{
static FileStream objStream;
[AssemblyInitialize()]
public static void Setup(TestContext testContext)
{
objStream = new FileStream(AppDomain.CurrentDomain.BaseDirectory + "\\AAA_UnitTestPerfMonitor.txt", FileMode.OpenOrCreate);
TextWriterTraceListener objTraceListener = new TextWriterTraceListener(objStream);
Trace.Listeners.Add(objTraceListener);
Trace.WriteLine("===================================");
Trace.WriteLine("App Start:" + DateTime.Now);
Trace.WriteLine("===================================");
}
[AssemblyCleanup]
public static void TearDown()
{
Trace.Flush();
objStream.Close();
}
}
我们可以为控制台执行相同的操作,将其连接到[AssemblyInitialize()]
,如下所示:
ConsoleTraceListener ctl = new ConsoleTraceListener(false);
ctl.TraceOutputOptions = TraceOptions.DateTime;
Trace.Listeners.Add(ctl);
然后你可以阅读文件并Assert
实际结果等于预期结果。
string[] fileLines = System.IO.File.ReadAllLines(AppDomain.CurrentDomain.BaseDirectory + "\\AAA_UnitTestPerfMonitor.txt");
Assert.IsTrue(fileLines[0] == "<< Console.Writeline code to print the help >> ");
可能还有其他方法。所以请稍等一下,看看是否还有其他人回答。
答案 2 :(得分:1)
在这里,您不必在一个地方写下您的逻辑。您可以利用命令模式。您将需要一个代表您对象状态的类。我们将其称为CustomObject。
public class CustomObject
{
//properties that represent the state, direction, inventory, etc.
public string Direction{get;set;}//etc.
}
public interface ICommand
{
string Execute(CustomObject obj);
}
public class InventoryCommand: ICommand
{
public string Execute(CustomObject obj)
{
//code to create the inventory string from CustomObject
return "Inventory String";
}
}
public class NorthCommand: ICommand
{
public string Execute(CustomObject obj)
{
//code to move the object to north
return "Command Information";
}
}
//In your test cases, you can do
CustomObject obj = new CustomObject();
//test for inventory command
var expectedOutput = "Expected Output";
var result = (new InventoryCommand()).Execute(obj);
Assert.Equal(result, expectedOuput);
//In your console program
if(command == "help")
{
Console.Writeline((new HelpCommand()).Execute(obj));
}
else if (command.Contains == "inv")
{
Console.Writeline((new InventoryCommand()).Execute(obj));
)
您可以根据您拥有的不同命令系列进一步隔离命令界面。