Tethos
is automated auto-mocking system which utilizes Castle.Windsor
as backbone for working with mocked dependencies used during unit testing. It is test framework agnostic. Tethos
supports all popular mocking libraries - Moq
, NSubstitute
and FakeItEasy
:
Package | NuGet |
---|---|
Tethos.Moq | |
Tethos.FakeItEasy | |
Tethos.NSubstitute |
Consider following example:
public class SystemUnderTest
{
public SystemUnderTest(IMockA mockA, IMockB mockB, IMockC mockC)
{
...
}
public int Exercise()
{
MockA.Get();
MockB.Get();
MockC.Get();
}
}
in order to resolve dependencies for SystemUnderTest
we will need to write following unit test:
[Fact]
public void Test()
{
var sut = new SystemUnderTest(
Mock.Of<IMockA>(),
Mock.Of<IMockB>(),
Mock.Of<IMockC>()
);
}
with Tethos
all you need to do is:
[Fact]
public void Test()
{
var sut = AutoMocking.Container.Resolve<SystemUnderTest>();
}
This saves time to manually injecting mocked dependencies leaving you more time to focus on test themselves. Tests like this also become easily maintainable. Furthermore, Tethos
will make sure to scan you test project references to load proper assemblies into the container.
To resolve mock to unit test simply resolve Mocking type and it will be resolved automatically.
In this example Moq
is used:
[Fact]
public void Test_Exercise()
{
// Arrange
var mock = Container.Resolve<Mock<IMockable>>();
mock.Setup(m => m.Get())
.Returns(expected);
...
}
within the scope of the test method dependencies, including mock instances will be exactly the same.
- Use
AutoMocking.Container
static property to retrieve container
public class ContainerFromBaseClass
{
[Fact]
public void Exercise_ShouldReturn42()
{
var sut = AutoMockingTest.Container.Resolve<SystemUnderTest>();
...
}
}
- Inherit from
AutoMockingTest
to have access toContainer
property.
public class ContainerFromBaseClass: AutoMockingTest
{
[Fact]
public void Exercise_ShouldReturn42()
{
var sut = this.Container.Resolve<SystemUnderTest>();
...
}
}
- Inject or initialize
IAutoMoqContainer
dependency using static factory method:AutoMocking.Create()
.
public class ContainerAsProperty: AutoMockingTest
{
public IAutoMoqContainer Container { get; }
public ContainerAsProperty()
{
Container = AutoMocking.Create();
}
[Fact]
public void Exercise_ShouldReturn42()
{
var sut = this.Container.Resolve<SystemUnderTest>();
...
}
}
Tethos
scans project's output assemblies, registers them to IoC container and install mocking interceptor.
Assemblies are selected according to prefix in the name. I.e, if you test assembly is named Project.Tests, then Tethos
will load every single Project.*
assembly into auto-mocking container.
Else, Tethos
will load project referenced assemblies into container.
Every single incoming dependency will be mocked if such dependency is an interface.
For example this dependency is will resolved without any issues.
public SystemUnderTest(IDependency dependency, ISubDependency subDependency)
{
...
}
while here
public SystemUnderTest(int dependency, string subDependency)
{
...
}
here, you will need to tell container what to resolve.
var sut = Container.Resolve<SystemUnderTest>(
new Arguments()
.AddTyped(42)
.AddTyped("foo")
);
in case there multiple dependencies with same or different types
public SystemUnderTest(int minValue, int maxValue)
{
...
}
You can use AddDependencyTo
extension method to add dependency to certain parameter in the constructor.
var sut = this.Container.Resolve<SystemUnderTest>(
new Arguments()
.AddDependencyTo<Concrete, int>(nameof(minValue), minValue)
.AddDependencyTo<Concrete, int>(nameof(maxValue), maxValue));
);
There are use cases when you can need to resolve parent dependency first before you can get to auto-mocked dependency. For this case, Tethos
has ResolveFrom<TParent, TChild>
extension method which will basically resolve mocked dependency in one go.
// Arrange
var mock = this.Container.ResolveFrom<SystemUnderTest, IMockable>();
vs.
// Arrange
_ = this.Container.Resolve<SystemUnderTest>();
var mock = this.Container.Resolve<IMockable>();
You can find demo projects code in /demo
folder. There are examples using Tethos
libraries with:
- xUnit
- NUnit
- MSTest
testing frameworks.
Internal dependencies can loaded into auto-mocking container. But due to possible performance caveats it's disabled by default. Check out Configuration section to figure our how to enable it.
Tethos
can behavior be configured using AutoMockingConfiguration
class instance.
Item | Description | Default value |
---|---|---|
IncludeNonPublicTypes | Enables internal types to be loaded into auto-mocking container | False |
Since AutoMockingConfiguration
is virtual you can override in the child class:
public class Test : AutoMockingTest
{
public override AutoMockingConfiguration AutoMockingConfiguration => new() { IncludeNonPublicTypes = false };
}
alternatively, you can override OnConfigurationCreated
method which allow you can edit configuration instance directly.
public class Test : AutoMockingTest
{
public override AutoMockingConfiguration OnConfigurationCreated(AutoMockingConfiguration configuration)
{
configuration.IncludeNonPublicTypes = true;
return base.OnConfigurationCreated(configuration);
}
}
Tethos uses Moq to auto-mock incoming dependencies. Mocks can resolved using Mock<>
wrapper type.
[Fact]
public void Test()
{
var mock = Container.Resolve<Mock<IMockable>>();
mock.Setup(m => m.Get()).Returns(42);
}
alternatively, Moq's proxy objects can be resolved as well
[Fact]
public void Test()
{
var mock = Container.Resolve<IMockable>();
Mock.Get(mock).Setup(m => m.Get()).Returns(42);
}
Tethos uses NSubstitute to auto-mock incoming dependencies. Since NSubstitute
alter object direct, mock can resolve using direct types.
[Fact]
public void Test()
{
var mock = Container.Resolve<IMockable>(); // <-- This will be mocked
mock.Get().Returns(42);
}
Tethos uses FakeItEasy to auto-mock incoming dependencies. FakeItEasy
also doesn't wrap mocked object, same here:
[Fact]
public void Test()
{
var mock = Container.Resolve<IMockable>(); // <-- This will be mocked
A.CallTo(() => mock.Get()).Returns(42)
}