Unit Testing a class with an internal constructor
I have a class called "Session" which exposes several public methods. I'd like to Unit Test these, however in production I need to control instantiation of "Session" objects, so delegate construction to to a SessionManager class and have made the Session's constructor internal.
I'd ideally like to test the Session class i开发者_JAVA技巧n isolation from the SessionManager which creates it/them to prove that the public interfaces exposed by the Session work as expected - but can't instantiate a Session from a test without using a SessionManager making my tests more complicated/less useful than they need to be.
What's the best way to deal with this?
Cheers,
Lenny.
Nothing prevents you from testing internals. Simply make the internals of your code visible to the test suite, by using the InternalsVisibleTo attribute: in the AssemblyInfo, add
[assembly:InternalsVisibleTo("TestSuiteAssembly")]
You could just make your unit test class inherit from Session (assuming your test framework doesn't require that you inherit from a specific class). For instance, with NUnit :
[TestFixture]
public class SessionTest : Session
{
public SessionTest()
: base() // call protected constructor
{
}
[Test]
public void TestSomething()
{
}
}
Alternatively, as a workaround, you could just create a TestSession that inherits from Session and exposes a public constructor. Inside your unit-test you then use the TestSession which basically does the same as the original Session object.
public class TestSession : Session
{
public TestSession() : base()
{
}
}
You want to use a product like TypeMock, which will allow you to create mocked (faked) instances of classes, like this:
var myInstance = Isolate.Fake.Instance<Session>();
// mock behavior here
// do assertions here
You can create instances of abstract classes with TypeMock as well, for the record.
I would question the value of making the session class constructor internal.
Generally this implies you are trying to stop other developers from using your class. Maybe it would be better to communicate how this particular piece of the application works and why you would only want to access the session from the session manager?
For .Net Core
you can modify .csproj
...
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>$(AssemblyName).Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
...
It will make internal stuff visible for your test project.
If you can leave with "protected internal" constructor, then, assuming that your tests are in different assembly, you can add InternalsVisibleTo attribute to your "to-be-tested-assembly". This would allow your tests to see internal members of to-be-tested-assembly".
Update For some reason I read that your constructor was protected. It is already internal so you are in a good position to use that attribute.
精彩评论