PaulH
PaulH

Reputation: 7843

unit testing with objects from 3rd party assemblies

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

Upvotes: 2

Views: 1500

Answers (3)

StingyJack
StingyJack

Reputation: 19469

If the classes aren't sealed/notinheritable, then you can derive a "mocked" class from the test target class and add your own constructor. So long as you aren't changing the base methods you are testing, this should work.

For example:

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

Upvotes: 0

Fabio
Fabio

Reputation: 3120

For unit tests, you can use the PrivateObject class (namespace Microsoft.VisualStudio.TestTools.UnitTesting) to create objects with private constructors and even test private methods.

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

Here's an example:

[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;
    }
}

It uses reflection in the same way as Jim's suggestion, but PrivateObject class encapsulates all the work to create the instance with private constructors.

Upvotes: 3

Jim Schubert
Jim Schubert

Reputation: 20357

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.

Upvotes: 1

Related Questions