Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 依赖于文件类和其他方法的测试方法_C#_Unit Testing_Methods_Moq - Fatal编程技术网

C# 依赖于文件类和其他方法的测试方法

C# 依赖于文件类和其他方法的测试方法,c#,unit-testing,methods,moq,C#,Unit Testing,Methods,Moq,因此,我创建了一个CsvParser来读取文件的内容并解析该文件的每一行。我有以下逻辑: public interface ICsvReader { List<string> ReadFromFile(string path); } public class CsvReader : ICsvReader { private readonly ICsvParser _csvParser; public CsvReader(ICsvParser cs

因此,我创建了一个CsvParser来读取文件的内容并解析该文件的每一行。我有以下逻辑:

public interface ICsvReader {
    List<string> ReadFromFile(string path);
}

public class CsvReader : ICsvReader 
{
    private readonly ICsvParser _csvParser;
    
    public CsvReader(ICsvParser csvParser) 
    {
        _csvParser = csvParser;
    }
    
    public List<string> ReadFromFile(string path) 
    {
        if (!File.Exists(path)) return null;

        var content = File.ReadAllLines(path);
        return ParseContent(content);
    }
    
    private List<string> ParseContent(StreamReader input) 
    {
        List<string> rows = new List<string>();
        foreach (var line in lines) {
            var updatedRow = _csvParser.ParseRow(line);
            lines.Add(updatedRow);
        }

        return rows;
    }
}

public interface ICsvParser 
{
    string ParseRow(string row);
}

public CsvParser : ICsvParser 
{
    public string ParseRow(string row) 
    {
       // Performing parsing here returning parsed row
    }
}
公共接口ICsvReader{
列表ReadFromFile(字符串路径);
}
公共类CsvReader:ICsvReader
{
专用只读ICsvParser\u csvParser;
公共CsvReader(ICsvParser csvParser)
{
_csvParser=csvParser;
}
公共列表ReadFromFile(字符串路径)
{
如果(!File.Exists(path))返回null;
var content=File.ReadAllLines(路径);
返回解析内容(content);
}
私有列表内容(StreamReader输入)
{
列表行=新列表();
foreach(行中的var行){
var updatedRow=_csvParser.ParseRow(行);
行。添加(updateRow);
}
返回行;
}
}
公共接口ICsvParser
{
字符串行(字符串行);
}
公共CsvParser:ICsvParser
{
公共字符串行(字符串行)
{
//在此处执行解析,返回已解析的行
}
}
这是可行的,但是需要为它编写测试。这就是我遇到问题的地方,我对如何处理这个问题有些困惑。首先,我的代码是耦合的/依赖于文件类的,所以在测试中肯定会尝试使用不理想的真实数据。我正在考虑使用模拟来传递假数据,但不确定这将如何工作。我不太熟悉moq,但我假设我想创建一个mock来将测试数据传递到ReadFromFile中,并检查预期结果是否正确

其次,我使用依赖注入来消除CsvReader和CsvParser之间的依赖关系,特别是ParseRow方法。我知道我可以使用moq来模拟interface+方法,但是因为PraseRow是在foreach循环中被调用的,这将如何影响设置?换句话说,每次调用时返回值都会不同

首先,我的代码是耦合的/依赖于文件类的

一般来说,尝试编写可以将流作为输入的API。您可以有一个附加方法,该方法采用文件路径,打开文件并将流转发给另一个方法。但这主要是为了方便。当您有内存流或其他数据源并且被迫将其保存到临时文件时,只接受文件路径的API非常烦人

如果采用文件路径的方法包含很少的逻辑,那么单元测试的好处就更少了。如果它只打开一个文件,我只需检查一下代码就可以了。并非每一行代码都需要被单元测试覆盖。或者更确切地说,单元测试的收益/成本比根据它是哪种代码而变化很大

当然,在测试中,它会尝试使用不理想的真实数据

我不认为使用真实数据的单元测试一定是坏的。当然,如果数据量很小,最好只使用硬编码字符串或字节数组作为测试数据的源。但是,在您的测试项目中添加一个更大、更复杂的文件作为内容文件,并使用该文件编写测试也可能很有用。这将在一定程度上降低单元测试的速度。如果这是一个问题,解决方案是将使用IO的测试放在一个运行频率较低的特殊类别中

我知道我可以使用moq来模拟interface+方法,但是因为PraseRow是在foreach循环中被调用的,这将如何影响设置

如果需要,您仍然可以一起测试这两个类。对于这样的类,我可能会认为它们是如此强耦合,单独测试它们不会增加很多好处。也就是说,你应该考虑测试它们的好处是否超过了额外的成本。 换句话说,每次调用时返回值都会不同


这取决于你。编写一个每次返回相同值的mock更容易。但是,如果您愿意,完全可以从列表中返回行。

1。抽象文件系统访问,避免与实现问题紧密耦合。2.设置模拟读取器时,在返回中使用SetupSequence或function delegate