2

I'm unit testing my C# application that Parses a CSV. I'm at 94% code coverage, because I can't force it to fail the try/catch blocks... I'm using CsvHelper from Nuget http://joshclose.github.io/CsvHelper

public void ParseCsv([FromBody] string csvText)
{
    var parseCsv = new XsvData(new[] { "\t", "," });
    try
    {
        using (var reader = new XsvReader(new StringReader(csvText)))
        {
            parseCsv.Read(reader, headerExists: true);
        }
    }
    catch (Exception)
    {
        var response = new HttpResponseMessage(HttpStatusCode.BadRequest)
        {
            Content = new StringContent("Unable to read CSV."),
            ReasonPhrase = "Invalid CSV"
        };

        throw new HttpResponseException(response);
    }
}

I've tried passing the most obscure strings I could think of to it, but it makes it through this, and errors out later on in the function..

[TestMethod]
//[ExpectedException(typeof(HttpResponseException))]
public void TestUploadCsv_UploadingCsvNonCsv()
{
    const string csvText = "fhfhk@- jhjfh@ajh- fjkqeqir%hjewq@hf- ujewqh$phfuw \n hfwu- ihfq&if*u@q- afuhwu- fhiue@wfhiuewhiuf";
    var context = GetMyFakeEntityDatabase();
    var controller = new MyController(context);
    controller.ParseCsv(csvText);
}

After the try/catch blocks, I have a section that enforces all the headers exist, and it fails there, but it should be failing during the reading, for this example. How do I force my unit test to fail? Any help is appreciated! Thanks in advance.

4

3 回答 3

0

我通过将它传递为 null 来解决这个问题,就像评论中推荐的 juharr 一样。

于 2014-10-28T20:49:59.527 回答
0

You should use Inversion of Control and inject the dependency into the controller instead of creating it in controller action. This way you can mock out the reader, and have it throw an except instead.

I'm going to write this example in terms of CsvHelper since that's what you say you are using, even though the example doesn't look like it.

Roughly:

public class MyController : Controller
{
    private readonly ICsvReader csv;

    public MyController( ICsvReader csv )
    {
        this.csv = csv;
    }
}

public class CsvReaderMock : ICsvReader
{
    public void Read()
    {
        throw new Exception();
    }
}

Now you can use your mock ICsvReader when testing, and it will throw an exception.

Also, you should only ever test a single method. If your method has dependencies, you should be passing them in instead of creating them, so you can test only the code in that method, and not of the classes it creates.

于 2014-10-01T20:49:59.297 回答
0

使用提供者模式和接口而不是具体类型,然后通过替换将引发异常的模拟对象来运行单元测试。

详细地:

  • 提取IXsvReader接口XsvReader
  • 实现一个新的具体实例,IXsvReader它会在Read. 为您希望单独处理的每个错误创建一个具体的实现类(在这种情况下,您只需要一个)。
  • 在包含该ParseCSV方法的类中,具有可设置的属性IXsvProvider。在同一类的构造函数中,将该属性设置为将返回“真实”阅读器的默认提供程序。这个接口只有一个方法,GetXsvReader(string text)
  • 在您的测试类中,使用 ParseCSV 函数新建类,然后注入一个 IXsvProvider(s),它返回您的“虚拟” IXsvReader,只要您尝试使用该方法,它就会简单地抛出异常。
于 2014-10-01T16:03:45.647 回答