Reputation: 7843
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
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
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://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
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