Firstly you should probably create an interface for A
as well, but if this is just a simple POCO data class, it might be better to just make its properties virtual
instead to allow for mocking. You have 3 options I think:
Inject A to the constructor of
B
if it is a class that will be used often (e.g. a logging class or something). Then you can create a mock version in your test to check howA
is used (remember, mocking is for testing behaviour with dependencies).public class A : IA { ... } public class B : IB { private readonly A a; public B(IA a) { this.a = a; } public void Func() { //... use this.a ... } } [Test] public void Func_AHasValue1_DoesAction1() { Mock<IA> mock = new Mock<IA>(); mock.Setup(a => a.somevalue).Returns("something"); B sut = new B(mock.Object); sut.Func(); mock.Verify(m => m.SomethingHappenedToMe()); }
- Pass
A
to the method if it is something thatB
needs to work with (as it seems here). You can still create a mock version for use in your tests. This is the same code as the above, butmock
is passed to the method instead of the constructor. This is the better method ifA
is some data class generated at runtime instead of a class with behaviour. Create a factory class for
A
and inject that into the constructor. Change the method to getA
instances from the factory and inject a mock factory in your tests to verify the behaviour.public class AFactory : IAFactory { public IA Create() { ... } } public class B : IB { private readonly IAfactory factory; public B(IAFactory factory) { this.factory = factory; } public void Func() { IA a = factory.Create(); //... use this.a ... } } [Test] public void Func_AHasValue1_DoesAction1() { Mock<IAFactory> mockFactory = new Mock<IAFactory>(); Mock<IA> mock = new Mock<IA>(); mockFactory.Setup(f => f.Create()).Returns(mock.Object); mock.Setup(a => a.somevalue).Returns("something"); B sut = new B(mockFactory.Object); sut.Func(); mock.Verify(m => m.SomethingHappenedToMe()); }
- Option 1 is the standard approach for classes that can be built without any runtime information (e.g. logging classes).
- Option 2 is better for when the input is only a data class that is generated at runtime (e.g. a user fills in a form and you have a POCO data class representing the form input).
- Option 3 is better when
A
is something that does have behaviour but can't be created without something generated at runtime.
You'll have to look at your application to see which is most applicable.