使用来自第三方程序集的对象进行单元测试
本文关键字:对象 单元测试 程序集 第三方 | 更新日期: 2023-09-27 18:30:13
我有一个Visual Studio 2008 C#.NET 3.5项目,正在为其实现单元测试,但遇到了一个问题。我的代码引用了一个第三方程序集,该程序集使用内部构造函数实现对象。
例如:
// in 3rd party assembly
public class Bar
{
// internal constructor
internal Bar();
public int Id { get; }
public string Name { get; }
public Foo Foo { get; }
}
public class Foo
{
// internal constructor
internal Foo();
public Collection<Bar> GetBars();
}
我想单元测试的一种方法是:
// in my assembly
public static Bar FindByName(this Collection<Foo> c, string name)
{
// search through the Foos to find the first bar with the matching name
}
然后这样测试:
void TestMethod()
{
Collection<Foo> foo_pool = new Collection<Foo>()
{
new Foo() { /*..*/ } // Error! ctor is inaccessible
};
Bar b = foo_pool.FindByName("some_name");
assert_equal (b.Name, "some_name");
}
但是,我不能创建Foo
或Bar
类型的对象。那么,我如何对我的方法进行单元测试呢?
感谢
对于单元测试,可以使用PrivateObject类(命名空间Microsoft.VisualStudio.TestTools.UnitTesting)创建具有私有构造函数的对象,甚至测试私有方法。
http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.privateobject(v=vs.90).aspx
http://www.gangleri.net/2007/11/15/PrivateObjects.aspx
这里有一个例子:
[TestMethod]
public void TestMethod2()
{
// Arrange
var po = new PrivateObject(typeof(MyObject));
var obj = (MyObject)po.Target;
// Act
var result = obj.Calculate(2);
// Assert
Assert.AreEqual(3, resul);
}
public class MyObject
{
internal MyObject()
{
}
public int Calculate(int a)
{
return 1 + a;
}
}
它使用反射的方式与Jim的建议相同,但PrivateObject类封装了使用私有构造函数创建实例的所有工作。
您可以使用反射来创建具有非公共构造函数的对象。请参阅SO.上的此问题
以下是来自上述链接的Ani的解决方案:
BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance;
CultureInfo culture = null; // use InvariantCulture or other if you prefer
object instantiatedType =
Activator.CreateInstance(typeToInstantiate, flags, null, parameter, culture);
Activator.CreateInstance将根据您给它的参数找到正确的构造函数。
如果类不是密封的/不可写的,那么您可以派生一个"嘲笑的";从测试目标类中初始化,然后添加自己的构造函数。只要你不改变你正在测试的基本方法,这应该是可行的。
例如:
public class MyBar:Bar
{
// internal constructor
public MyBar(object throwaway)
{
//call base constructor if necessary
};
public int Id { get; }
public string Name { get; }
public Foo Foo { get; }
}