使用来自第三方程序集的对象进行单元测试

本文关键字:对象 单元测试 程序集 第三方 | 更新日期: 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");
}

但是,我不能创建FooBar类型的对象。那么,我如何对我的方法进行单元测试呢?

感谢

使用来自第三方程序集的对象进行单元测试

对于单元测试,可以使用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; }
}