TL;DR
I can't seem to get InternalsVisibleTo to work with my Unit Tests
Background
I'm currently developing a library where I'd like to make some (but not all) classes internal to avoid confusing the users. Only SOME of the classes should be public from that dll.
I figured this would be a good project to learn how to deal with the internal keyword in C#.
Whenever I make a new project, I find myself using a variant of DDD, where I'll split up responsibilities into different DLL's, but for the sake of this question, think of my project structure like this (from top to bottom):
The executable using my library
The library that I'm developing
A unit test library for unit-testing my library
Testing tools library, containing base class for all unit tests
For a working example of the architecture, you can look at my HelloWorld project over on github. This example does not replicate the problem here though, it only serves to illustrate how I typically layer my code.
I'll often create a base class for my unit tests that creates mocks for any type that I'm testing, i.e. this example:
public class TestsFor<TInstance> where TInstance : class
{
protected MoqAutoMocker<TInstance> AutoMock { get; set; }
protected TInstance Instance { get; set; }
public TestsFor()
{
AutoMock = new MoqAutoMocker<TInstance>();
RunBeforeEachUnitTest(); // virtual
Instance = AutoMock.ClassUnderTest;
RunAfterEachUnitTest(); // virtual
}
}
Problem
The Unit-Tests that I write often take them form of:
public class ReportServiceTests : TestsFor<ReportService>
{
[Fact]
public async Task CreateReport_WhenCalled_LogsTheCall()
{
// Act
await Instance.CreateReport();
// Assert
GetMockFor<ILogger>().Verify(logger => logger.Enter(Instance, nameof(Instance.CreateReport)), Times.Once());
}
}
Where each Unit test will derive the TestsFor<T> class in order to give me an out-of-the-box mocked test class. However, even though I've marked my internal classes with InternalsVisibleTo pointing them to both the unit-test assembly as well as the test-tools assembly (where the unit-test baseclass is) I'm STILL getting Inconsistent accessibility errors.
Does anyone know how to get around this?
The problem you're running into is that you are trying to create a class that is more accessible than its base class.
You can delegate instead of deriving:
public class ReportServiceTests
{
private Tests tests = new Tests();
[Fact]
public async Task CreateReport_WhenCalled_LogsTheCall()
{
tests.CreateReport_WhenCalled_LogsTheCall();
}
private class Tests : TestsFor<ReportService>
{
public async Task CreateReport_WhenCalled_LogsTheCall()
{
// Act
await Instance.CreateReport();
// Assert
GetMockFor<ILogger>().Verify(logger => logger.Enter(Instance, nameof(Instance.CreateReport)), Times.Once());
}
}
}
Related
We are creating unit tests in XUnit for one of our projects our ASP.NET application. In the project, we are trying to mock out a particular third party client we don't have access to the source code and does not provide an interface (just a client object we can create). To fix this, we wrote a wrapper class and an interface to that class so we can mock out the functionality we need for that client. This part is all good.
One of the methods we created in the wrapper class and interface was a GetInnerChannel method to get a property from the client (which we want to mock out). However, that method returns an Interface of IClientChannel from System.ServiceModel.
public IClientChannel GetInnerChannel()
{
return client.InnerChannel;
}
It seems harmless, but, in our mock setup, we are unable to create a fake IClientChannel object that is useful for the method we are testing. Here is our unit test code for clarification:
client.Setup(i => i.GetInnerChannel()).Returns(GetClientChannel());
In the Returns call, you will see we are returning a method return which we currently set to null for now. This is because we cannot instantiate an interface. When I dived into debugging, I found that the object that is being sent back in place of the interface during normal operation is a System.Runtime.Remoting.Proxies.__TransparentProxy object. A little investigation into the __TransparentProxy class is that it is an internal sealed class (which means we cannot instantiate that in our unit test code).
Unfortunately, the method we are testing is using the InnerChannel in this way:
public List<EquifaxQuestion> GetEquifaxQuestions(User basicUserInfo, IEnumerable<AddressViewModel> Addresses)
{
try
{
InitialResponse response;
using (new OperationContextScope(client.GetInnerChannel()))
{
OperationContext.Current.OutgoingMessageHeaders.Add(
new EquifaxSecurityHeader(appID, username, password));
response = client.SubmitInitialInteraction(GenerateInitialRequest(basicUserInfo, Addresses));
}
Which I don't if we can replace the GetInnerChannel call and thus we require a mock of it to just get through the unit test since we must mock out our client.
Is there another way I can return a value or object that is useful for GetInnerChannel()? Am I missing a step in my mock setups? Or is Moq and other mocking frameworks incapable to do what I need to do? Or is the method I am trying unit test against unable to be unit tested? Thank you in advance.
Basically the solution for this was a lot of wrappers and interfaces to work in WCF. It is quite lengthy, but this blog post does a better job. https://weblogs.asp.net/cibrax/unit-tests-for-wcf
In short, if you have static, sealed, or other third party class you can't mock, wrap it in a simple task with all public methods written in them with them calling your third party class's method and then create an interface for the wrapper. In your unit tests, use the interface and in your normal code, use your wrapper class.
This is possible without having to write any more wrappers. It is important to understand the principle of indirection that gets introduced by adding an interface. Every interface added is an opportunity to isolate the abstraction and make it look and feel different.
I have attached the important snippets below, due to expected brevity I am not attaching entire solution.
Quick explaination of classes and usage hierarchy -
1. IInnerChannel is the interface exposed by the third party library.
2. IClientChannelWrapper is the wrapper class created in order to hide inner interface from calling clients.
3. ClassUsingChannelWrapper is the class that invokes this logic and in our unit test its method is going to be our sut (subject under test).
Code goes as below -
The IInnerChannel interface declaration-
public interface IInnerChannel
{
string TheInnerChannelMethod();
}
The InnerChannel implementation (probably in the third party library in your case)-
public class InnerChannelImplementation : IInnerChannel
{
public InnerChannelImplementation()
{
}
public string TheInnerChannelMethod()
{
var result = "This is coming from innser channel.";
Console.WriteLine(result);
return result;
}
}
The wrapper created by you around the inner channel -
public interface IClientChannelWrapper
{
void DoSomething();
IInnerChannel GetTheInnerChannelMethod();
}
The wrapper interface's implementation -
public class ClientChannelWrapperImplementation : IClientChannelWrapper
{
public ClientChannelWrapperImplementation()
{
}
public void DoSomething()
{
Console.WriteLine("The DoSomething Method!");
}
public IInnerChannel GetTheInnerChannelMethod()
{
InnerChannelImplementation imp = new InnerChannelImplementation();
return imp;
}
}
The class that calls your wrapper's implementation. This class is going to be your SUT when implementing unit tests -
public class ClassUsingChannelWrapper
{
IClientChannelWrapper _wrapper;
public ClassUsingChannelWrapper(IClientChannelWrapper wrapper)
{
_wrapper = wrapper;
}
public void TheClientChannelConsumerMethod()
{
IInnerChannel theChannel = _wrapper.GetTheInnerChannelMethod();
var result = theChannel.TheInnerChannelMethod();
Console.WriteLine(result);
}
}
Finally, the unit test with mocks mimicking behaviour of both interfaces. Notice how mocked client channel wrapper is returning mocked internal channel object which returns pre-programmed value.
public class UnitTest1
{
[Fact]
public void Test1()
{
//Arrange
Mock<IInnerChannel> innerChannelMock = new Mock<IInnerChannel>();
innerChannelMock.Setup(i => i.TheInnerChannelMethod()).Returns("This
is a test from mocked object.");
Mock<InterfaceUt.IClientChannelWrapper> mockClientWrapper = new
Mock<IClientChannelWrapper>();
mockClientWrapper.Setup(m =>
m.GetTheInnerChannelMethod()).Returns(innerChannelMock.Object);
//Act
ClassUsingChannelWrapper sut = new
ClassUsingChannelWrapper(mockClientWrapper.Object);
sut.TheClientChannelConsumerMethod();
//Assert
innerChannelMock.Verify();
mockClientWrapper.Verify();
}
}
Running this unit test prints
"This is a test from mocked object."
Essentially, your unit test is targeting only the client code that attempts to use your interface behaviour. This does not test the implementation of your wrapper. If you want to achieve that you will have to create a new instance of wrapper class instead of mock object and feed it with inner channel's mock object.
I'm trying to add tests to a webforms project. There's a static method to grab lines from resource files. One of the classes I'm trying to test, relies on grabbing text from the resource file.
public static class MyStaticClass {
public static string getText(String name)
{
String s = HttpContext.GetGlobalResourceObject("MyResources", name).ToString();
return s;
}
}
public class ClassUnderTest
{
// returns: "Hey it's my text"
private string _eg = MyStaticClass.getText("label_in_resources.resx_file")
}
class UnitTests
{
[Test]
public void TestMyClass()
{
ClassUnderTest _cut = new ClassUnderTest();
// errors out because ClassUnderTest utilizes getText
// which requires HttpContext.GetGlobalResourceObject
// ... other stuff
}
}
Note: these are simplistic examples.
The issue is that I get a Test Failed with the message:
Message: System.NullReferenceException : Object reference not set to an instance of an object.
With my sleuthing, I've determined that this is because HttpContext is null during these tests.
I've looked at quite a few SO posts on mocking HttpContext but I don't think that I fully understand what exactly they're doing as they're typically dealing with MVC and not Webforms. Still most of them use HttpContextBase and/or HttpContextWrapper but again, I'm not sure how to implement them.
Also - I'm not directly testing the getText method. I know it works. I'm testing a class that uses it. Will mocking the HttpContext even help in this situation?
I do realize that this is sort of a hybrid of a unit test / integration test, so if this isn't the best way, I'm all ears... or.. eyes rather.
Edit
For now, I modified my getText method to return the key (name) if the result of HttpContext.GetGlobalResourceObject is null. Then I updated my tests to expect the key instead of the value. It's not ideal, but it works and allows me to continue. If there's a better way, please let me know.
public static class MyStaticClass {
public static string getText(String name)
{
String s = HttpContext.GetGlobalResourceObject("MyResources", name);
return s != null ? s.ToString() : name;
}
}
Original answer with Fakes (see below for dealing with removing static)
So there's one caveat that I completely forgot about until I just tried to do this. I am pretty sure Fakes still requires Enterprise version of VS. I don't know if there's a way to get it to work with NUnit, but when you aren't able to change the code sometimes you have to just deal with it.
Here's an example of Shimming your static method. You don't need to worry about HttpContext (yet) since you aren't using it directly. Instead you can Shim your getText(string) method.
Actual Business Project
namespace FakesExample
{
public class MyStaticClass
{
public static string GetText(string name)
{
throw new NullReferenceException();
}
}
}
Your Unit Test Project
using System;
using Microsoft.QualityTools.Testing.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace FakesExampleTests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
using (ShimsContext.Create())
{
FakesExample.Fakes.ShimMyStaticClass.GetTextString = (s) =>
{
return "Go away null reference";
};
Console.WriteLine(FakesExample.MyStaticClass.GetText("foo"));
}
}
}
}
I actually ran this so I know it works. What happens is that even though GetText will always throw a NullReferenceException when called, our Shim of it returns our own custom message.
You may have to make a Visual Studio Test Project.
In your Unit Test project, right-click your reference and say "Add Fakes". It will generate all of the Shims and Stubs for your assembly.
Process of removing the static
The best solution is to actually work towards removing the static. You've already hit one major reason to not use them.
Here's how I would go about removing the static and removing the dependency on HttpContext
public interface IResourceRepository
{
string Get(string name);
}
public class HttpContextResourceRepository : IResourceRepository
{
public string Get(string name)
{
return HttpContext.GetGlobalResourceObject("MyResources", name).ToString();
}
}
public class MyFormerStaticClass
{
IResourceRepository _resourceRepository;
public MyFormerStaticClass(IResourceRepository resourceRepository)
{
_resourceRepository = resourceRepository;
}
public string GetText(string name)
{
return _resourceRepository.Get(name);
}
}
I would then leverage Dependency Injection to handle the creation of my HttpContextResourceRepository and MyStaticClass (which should probably also be interfaced) in the actual business code.
For the unit test, I would mock the implementation
[TestFixture]
public class UnitTest1
{
[Test]
public void TestMethod1()
{
var repoMock = new Mock<IResourceRepository>();
repoMock.Setup(repository => repository.Get("foo")).Returns("My Resource Value");
var formerStatic = new MyFormerStaticClass(repoMock.Object);
Console.WriteLine(formerStatic.GetText("foo"));
}
}
Going this route, you can create any number of IResourceRepository implementations and swap them whenever you want.
I have below code which I want to unit test.
public abstract class Manager : MyPermissions, IManager
{
public IManager empManager { get; set; }
public void UpdatePermission()
{
if (empManager != null)
empManager.UpdatePermissions();
}
}
I don't have an class that derives from the above class within the same library otherwise I would have preferred to test the derived class for testing the above code. For now I have below test which I am running but it actually doesn't hit the actual code for testing.
[TestMethod]
public void empManagerGetSet()
{
using (ShimsContext.Create())
{
StubIManager sManager;
sManager = new StubIManager();
sManager.empManagerGet = () => { return (IManager)null; };
var result = sManager.empManagerGet;
Assert.IsNotNull(result);
}
}
Is there any other approach I can use to write a better UT in this scenario?
You don't say what your MyPermissions class looks like, if it has a constructor and if so what it does.. so this might not be the right approach. Note, you'd also need to implement stubs for any abstract methods defined in the Manager class.
If you just want to test the empManager property, you can just create a testable derived type in your test project and test the properties on that. This would give you something like this:
class TestableManager : Manager {
}
Then have a test something like this:
[TestMethod]
public void TestManagerPropertyRoundTrip {
var sut = new TestableManager();
Assert.IsNull(sut.empManager);
sut.empManager = sut;
Assert.AreEqual(sut, sut.empManager);
}
You can also test any other methods on the Manager class, via the TestableManager, since it only exists to make the class concrete.
There's a suggestion in the comments on your question that there is no point testing public properties. This is somewhat opinion based. I tend to take the view that if you were following a test first based approach, you wouldn't necessarily know that the properties were going to be implemented using auto properties, rather than a backing field. So, the behaviour of being able to set a property and retrieve it again is something that I would usually test.
I am new to TDD and I am using Moq as my mocking framework.
I am trying to check if a method has been called in my class.
The class is not implementing any Interface.
var mockFooSaverService = new Mock<FooSaverService>();
mockFooSaverService.Verify(service => service.Save(mockNewFoo.Object));
to make this work I found here that I have to make the Save() method as a Virtual method.
Question:
What are the consequences of using Virtual keyword for all methods in a class just for the sake of making it testable?
TL;DR
As per the comments, the need for the virtual keyword indicates that your class hierarchy is too tightly coupled, and you should apply SOLID principles to decouple them from eachother. This has the "happy" side effect of making your class hierarchy easier to Unit Test, as dependencies can be mocked via the interface abstraction.
In more Detail
The need make all public methods virtual to allow Moq to override them is frequently indicative of a separation of concerns or class coupling smell.
e.g. this scenario needed virtual methods because class under test has multiple concerns, and there was a need to mock one method and actually invoke another method in the same system under test.
As per #JonSkeet's comment, it is commonplace SOLID best practice to abstract dependencies as interfaces. As it stands, your class under test (May I call it "Controller"?) is dependent on the concrete FooSaverService to save Foos.
By applying the Dependency Inversion Principle, this coupling can be loosened, by abstracting just the externally useful methods, properties and events of FooSaverService to an interface (IFooSaverService), and then
FooSaverService implements IFooSaverService
Controller depends only on IFooSaverService
(Obviously, there are likely other optimizations, e.g. to make the IFooSaverService generic, e.g. ISaverService<Foo> but not in scope here)
Re : Mock<Foo> - it is fairly uncommon to need to Mock simple data storage classes (POCO's, Entities, DTO's etc) - since these will typically retain data stored in them and can be reasoned over directly in unit tests.
To answer your question re implications of Virtual (which is hopefully less relevant now):
You are breaking the (polymorphic) Open and Closed Principle - it is inviting others to override behaviour without deliberately designing for this - there may be unintended consequence.
As per Henk's comment, there will be a small performance impact in administering the virtual method table
A code example
If you put all this together, you'll wind up with a class hierarchy like so:
// Foo is assumed to be an entity / POCO
public class Foo
{
public string Name { get; set; }
public DateTime ExpiryDate { get; set; }
}
// Decouple the Saver Service dependency via an interface
public interface IFooSaverService
{
void Save(Foo aFoo);
}
// Implementation
public class FooSaverService : IFooSaverService
{
public void Save(Foo aFoo)
{
// Persist this via ORM, Web Service, or ADO etc etc.
}
// Other non public methods here are implementation detail and not relevant to consumers
}
// Class consuming the FooSaverService
public class FooController
{
private readonly IFooSaverService _fooSaverService;
// You'll typically use dependency injection here to provide the dependency
public FooController(IFooSaverService fooSaverService)
{
_fooSaverService = fooSaverService;
}
public void PersistTheFoo(Foo fooToBeSaved)
{
if (fooToBeSaved == null) throw new ArgumentNullException("fooToBeSaved");
if (fooToBeSaved.ExpiryDate.Year > 2015)
{
_fooSaverService.Save(fooToBeSaved);
}
}
}
And then you'll be able to test your class which has the IFooSaverService dependency as follows:
[TestFixture]
public class FooControllerTests
{
[Test]
public void PersistingNullFooMustThrow()
{
var systemUnderTest = new FooController(new Mock<IFooSaverService>().Object);
Assert.Throws<ArgumentNullException>(() => systemUnderTest.PersistTheFoo(null));
}
[Test]
public void EnsureOldFoosAreNotSaved()
{
var mockFooSaver = new Mock<IFooSaverService>();
var systemUnderTest = new FooController(mockFooSaver.Object);
systemUnderTest.PersistTheFoo(new Foo{Name = "Old Foo", ExpiryDate = new DateTime(1999,1,1)});
mockFooSaver.Verify(m => m.Save(It.IsAny<Foo>()), Times.Never);
}
[Test]
public void EnsureNewFoosAreSaved()
{
var mockFooSaver = new Mock<IFooSaverService>();
var systemUnderTest = new FooController(mockFooSaver.Object);
systemUnderTest.PersistTheFoo(new Foo { Name = "New Foo", ExpiryDate = new DateTime(2038, 1, 1) });
mockFooSaver.Verify(m => m.Save(It.IsAny<Foo>()), Times.Once);
}
}
TL;DR;
Another good answer is - making classes extendable, and providing virtual methods (i.e. the possibility to extend them) is "feature" of that class. And this feature needs to be supported and tested as any other feature.
Much better explanation can be read on Eric Lippert's blog.
I have been making a little toy web application in C# along the lines of Rob Connery's Asp.net MVC storefront.
I find that I have a repository interface, call it IFooRepository, with methods, say
IQueryable<Foo> GetFoo();
void PersistFoo(Foo foo);
And I have three implementations of this: ISqlFooRepository, IFileFooRepostory, and IMockFooRepository.
I also have some test cases. What I would like to do, and haven't worked out how to do yet, is to run the same test cases against each of these three implementations, and have a green tick for each test pass on each interface type.
e.g.
[TestMethod]
Public void GetFoo_NotNull_Test()
{
IFooRepository repository = GetRepository();
var results = repository. GetFoo();
Assert.IsNotNull(results);
}
I want this test method to be run three times, with some variation in the environment that allows it to get three different kinds of repository. At present I have three cut-and-pasted test classes that differ only in the implementation of the private helper method IFooRepository GetRepository(); Obviously, this is smelly.
However, I cannot just remove duplication by consolidating the cut and pasted methods, since they need to be present, public and marked as test for the test to run.
I am using the Microsoft testing framework, and would prefer to stay with it if I can. But a suggestion of how to do this in, say, MBUnit would also be of some interest.
Create an abstract class that contains concrete versions of the tests and an abstract GetRepository method which returns IFooRepository.
Create three classes that derive from the abstract class, each of which implements GetRepository in a way that returns the appropriate IFooRepository implementation.
Add all three classes to your test suite, and you're ready to go.
To be able to selectively run the tests for some providers and not others, consider using the MbUnit '[FixtureCategory]' attribute to categorise your tests - suggested categories are 'quick' 'slow' 'db' 'important' and 'unimportant' (The last two are jokes - honest!)
In MbUnit, you might be able to use the RowTest attribute to specify parameters on your test.
[RowTest]
[Row(new ThisRepository())]
[Row(new ThatRepository())]
Public void GetFoo_NotNull_Test(IFooRepository repository)
{
var results = repository.GetFoo();
Assert.IsNotNull(results);
}
If you have your 3 copy and pasted test methods, you should be able to refactor (extract method) it to get rid of the duplication.
i.e. this is what I had in mind:
private IRepository GetRepository(RepositoryType repositoryType)
{
switch (repositoryType)
{
case RepositoryType.Sql:
// return a SQL repository
case RepositoryType.Mock:
// return a mock repository
// etc
}
}
private void TestGetFooNotNull(RepositoryType repositoryType)
{
IFooRepository repository = GetRepository(repositoryType);
var results = repository.GetFoo();
Assert.IsNotNull(results);
}
[TestMethod]
public void GetFoo_NotNull_Sql()
{
this.TestGetFooNotNull(RepositoryType.Sql);
}
[TestMethod]
public void GetFoo_NotNull_File()
{
this.TestGetFooNotNull(RepositoryType.File);
}
[TestMethod]
public void GetFoo_NotNull_Mock()
{
this.TestGetFooNotNull(RepositoryType.Mock);
}
[TestMethod]
public void GetFoo_NotNull_Test_ForFile()
{
GetFoo_NotNull(new FileRepository().GetRepository());
}
[TestMethod]
public void GetFoo_NotNull_Test_ForSql()
{
GetFoo_NotNull(new SqlRepository().GetRepository());
}
private void GetFoo_NotNull(IFooRepository repository)
{
var results = repository. GetFoo();
Assert.IsNotNull(results);
}
To Sum up, there are three ways to go:
1) Make the tests one liners that call down to common methods (answer by Rick, also Hallgrim)
2) Use MBUnit's RowTest feature to automate this (answer by Jon Limjap). I would also use an enum here, e.g.
[RowTest]
[Row(RepositoryType.Sql)]
[Row(RepositoryType.Mock)]
public void TestGetFooNotNull(RepositoryType repositoryType)
{
IFooRepository repository = GetRepository(repositoryType);
var results = repository.GetFoo();
Assert.IsNotNull(results);
}
3) Use a base class, answer by belugabob
I have made a sample based on this idea
public abstract class TestBase
{
protected int foo = 0;
[TestMethod]
public void TestUnderTen()
{
Assert.IsTrue(foo < 10);
}
[TestMethod]
public void TestOver2()
{
Assert.IsTrue(foo > 2);
}
}
[TestClass]
public class TestA: TestBase
{
public TestA()
{
foo = 4;
}
}
[TestClass]
public class TestB: TestBase
{
public TestB()
{
foo = 6;
}
}
This produces four passing tests in two test classes.
Upsides of 3 are:
1) Least extra code, least maintenance
2) Least typing to plug in a new repository if need be - it would be done in one place, unlike the others.
Downsides are:
1) Less flexibility to not run a test against a provider if need be
2) Harder to read.