2

I have a Visual Studio 2008 C# .NET 3.5 project that I am implementing unit tests for, but I've run in to a problem. My code references a 3rd party assembly that implements objects with internal constructors.

For example:

// 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();
}

One method of mine that I would like to unit test is this:

// 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
}

And test it like this:

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");
}

But, I can't create objects of type Foo or type Bar. So, how can I unit test my method?

Thanks

4

3 回答 3

3

对于单元测试,您可以使用 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 类封装了使用私有构造函数创建实例的所有工作。

于 2012-04-05T16:46:10.987 回答
1

You can use reflection to create objects with non-public constructors. See this question on SO.

Here's Ani's solution from the above link:

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 will find the correct constructor based on the parameters you give it.

于 2012-04-05T16:32:55.693 回答
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; }
}
于 2012-04-05T16:45:51.517 回答