使用EPPlus的单元测试类 [英] Unit testing classes that use EPPlus

查看:65
本文介绍了使用EPPlus的单元测试类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了使用EPPlus的单元测试课程的问题。在我看来,我有两个选择。



我可以嘲笑&将HttpPostedFileBase注入方法,或者我可以模拟&注入EPPlus ExcelPackage类。



模拟HttpPostedFileBase至少要进行一次真正的模拟似乎很有限。我可以模拟文件的基本属性(MIME类型,文件名等),但是以一种允许测试实际与之交互的方式模拟其InputStream似乎非常困难。我唯一能想到的解决方案是提供一个真正的excel文件,使用它创建一个真正的FileStream,并将该FileStream分配给我的模拟HttpPostedFileBase的InputStream。

  const string FakeFileName = TestExcelFile.xlsx;但这从技术上讲是一个集成测试,而不是单元测试。 //实际Excel文件的路径
var fileStream = new FileStream(FilePath,FileMode.Open);
var fakeFile = A.Fake< HttpPostedFileBase>();
A.CallTo(()=> fakeFile.InputStream).Returns(fileStream);




我想如果我想做一个实际的单元测试,我可以模拟并注入EPPlus ExcelPackage类。然后,我可以模拟相关的工作表,列和单元类,可以动态设置其属性以适合我的测试条件,而永远不要触摸真实文件。问题是,大多数EPPlus类都是密封的,因此我无法使用FakeItEasy对其进行模拟。我尝试为它们创建包装器类(请参见下文),所以我可以模拟包装器类……但是我需要模拟/包装的某些类具有内部构造函数,因此无法实例化它们。 (我确实尝试过使用一些丑陋的方法解决内部构造函数问题,但没有成功。)因此,使用该选项使我无所适从。



我仍然是一个新手,还有很多东西要学。也许我的包装器类概念不正确,而我做错了。有没有办法解决我看不见的问题,还是应该放弃使用真正的excel文件,并将其称为集成测试?到目前为止,这就是我的目标。

 公共类ExcelWorksheetsWrapper:IEnumerable< ExcelWorksheet> 
{
公共只读ExcelWorksheets _excelWorksheets;

public ExcelWorksheetsWrapper()
{
//内部构造函数,无法实例化
_excelWorksheets = new ExcelWorksheets();
}

public ExcelWorksheet Add(string worksheetName)
{
return _excelWorksheets.Add(worksheetName);
}

公共IEnumerator< ExcelWorksheet> GetEnumerator()
{
return _excelWorksheets.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return _excelWorksheets.GetEnumerator();
}
}


解决方案

模拟第三方库常常使人痛苦不堪,并创建了难以理解的单元测试。



每个测试都应该简短,易读且易于理解。



通常最好围绕第三方库创建包装器类,并在其上使用接口,这样才能更好地理解预期的成功操作。



这些课程。然后,您可以创建实现这些接口的模拟对象,仅用于测试。



不过,说起来容易做起来容易。显然,第三方库会发生某些事情,这些事情不仅会被切断代码并进行有意义的测试。



在这种情况下,您仍然应该使用您自己的界面,但是将那些类型的单元测试隔离到仅依赖于第三方库的最低限度。



尝试看看SOLID编程模式。使用这种模式构建的系统通常更易于测试,因为所有组件都是松散耦合的。



http://zh.wikipedia.org/wiki/Solid_(面向对象的设计)


I am having issues unit testing classes that use EPPlus. In my mind, I have two options.

I can mock & inject the HttpPostedFileBase into a method, or I can mock & inject the EPPlus ExcelPackage class.

Mocking the HttpPostedFileBase, at least doing a true mock, seems limited. I can mock the basic properties on the file (MIME type, filename, etc), but to mock its InputStream in a way that allows the tests to actually interact with it, seems extremely difficult. The only solution I can come up with is to provide a real excel file, create a real FileStream with it, and assign that FileStream to my mock HttpPostedFileBase's InputStream. But then it's technically an integration test, not a unit test.

const string FakeFileName = "TestExcelFile.xlsx"; // path to an actual excel file
var fileStream = new FileStream(FilePath, FileMode.Open);
var fakeFile = A.Fake<HttpPostedFileBase>();
A.CallTo(() => fakeFile.InputStream).Returns(fileStream);



I figured if I wanted to do an actual unit test, I could mock and inject the EPPlus ExcelPackage class instead. I could then mock the related Worksheet, Columns & Cell classes, setting their properties dynamically to fit the conditions of my test, while never touching a real file. The problem is, most of the EPPlus classes are sealed, so I can't mock them with FakeItEasy. I tried creating wrapper classes for them (see below), so I could mock the wrapper class instead... but some of the classes I need to mock/wrap have internal constructors, so I can't instantiate them. (I did try getting around the internal constructor problem using a couple of ugly hacks, but didn't have success.) And so I've hit a wall with this option.

I am still a novice and have a lot to learn. Perhaps my concept of a wrapper class is incorrect, and I am doing it wrong. Is there a way around this I can't see, or should I just give up, use a real excel file, and call it an integration test? So far, that's what I am leaning towards.

public class ExcelWorksheetsWrapper : IEnumerable<ExcelWorksheet>
{
    public readonly ExcelWorksheets _excelWorksheets;

    public ExcelWorksheetsWrapper()
    {
        // internal constructor, can't instantiate
        _excelWorksheets = new ExcelWorksheets();       
    }

    public ExcelWorksheet Add(string worksheetName)
    {
        return _excelWorksheets.Add(worksheetName);
    }

    public IEnumerator<ExcelWorksheet> GetEnumerator()
    {
        return _excelWorksheets.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _excelWorksheets.GetEnumerator();
    }
}

解决方案

Mocking a third-party library is often a pain in the neck and creates cryptic unit tests.

Each test should be short, easy to read and understandable. It should be easy looking at the test to understand what the intended successful operation should be.

It's usually better to create wrapper classes around third-party libraries, and use interfaces on those classes. You can then create mock objects that implement those interfaces just for testing.

Still, that is easier said then done. Obviously there are going to be things that third-party libraries do that can't just be cut-out of code and make for meaningful tests.

In those cases, you still should use your own interfaces, but isolate those kinds of unit tests to just the bare minimum that are dependent upon the third-party library.

Try taking a look at the SOLID programming pattern. Systems built using that pattern are often easier to test because everything is loosely coupled.

http://en.wikipedia.org/wiki/Solid_(object-oriented_design)

这篇关于使用EPPlus的单元测试类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆