我有一个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
类型的对象。那么,我该如何对我的方法进行单元测试呢?
由于
答案 0 :(得分:3)
对于单元测试,您可以使用PrivateObject类(名称空间Microsoft.VisualStudio.TestTools.UnitTesting)来创建具有私有构造函数的对象,甚至可以测试私有方法。
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类封装了使用私有构造函数创建实例的所有工作。
答案 1 :(得分:1)
您可以使用反射来创建具有非公共构造函数的对象。请参阅this question on 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将根据您提供的参数找到正确的构造函数。
答案 2 :(得分:0)
如果类没有密封/不可接受,那么您可以从测试目标类派生一个“模拟”类并添加自己的构造函数。只要你没有改变你正在测试的基本方法,这应该可行。
例如:
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; }
}