Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hlaueriksson/fceb24a6d9fb591519a5988be25dc191 to your computer and use it in GitHub Desktop.
Save hlaueriksson/fceb24a6d9fb591519a5988be25dc191 to your computer and use it in GitHub Desktop.
2017-02-28-automocking-and-the-dependency-inversion-principle
namespace ConductOfCode.Core
{
public interface IHelloWorld
{
string GetMessage();
}
internal class HelloWorld : IHelloWorld
{
private readonly IFoo _foo;
private readonly IBar _bar;
public HelloWorld(IFoo foo, IBar bar)
{
_foo = foo;
_bar = bar;
}
public string GetMessage()
{
return _foo.GetFoo() + _bar.GetBar();
}
}
public interface IFoo
{
string GetFoo();
}
internal class Foo : IFoo
{
public string GetFoo() => "Hello";
}
public interface IBar
{
string GetBar();
}
internal class Bar : IBar
{
public string GetBar() => ", World!";
}
}
using StructureMap;
namespace ConductOfCode.Core
{
public class HelloWorldRegistry : Registry
{
public HelloWorldRegistry()
{
For<IHelloWorld>().Use<HelloWorld>();
For<IFoo>().Use<Foo>();
For<IBar>().Use<Bar>();
}
}
}
using System;
using StructureMap;
namespace ConductOfCode
{
public static class IoC
{
private static readonly Lazy<Container> Lazy = new Lazy<Container>(CreateContainer);
public static IContainer Container => Lazy.Value;
private static Container CreateContainer()
{
return new Container(_ =>
_.Scan(x =>
{
x.AssembliesAndExecutablesFromApplicationBaseDirectory();
x.LookForRegistries();
})
);
}
}
}
using System;
using ConductOfCode.Core;
namespace ConductOfCode
{
public class Program
{
public static void Main(string[] args)
{
IoC.Container.AssertConfigurationIsValid();
var helloWorld = IoC.Container.GetInstance<IHelloWorld>();
Console.WriteLine(helloWorld.GetMessage());
}
}
}
using ConductOfCode.Core;
using ConductOfCode.Tests.Fakes;
using Moq;
using Should;
using Xunit;
namespace ConductOfCode.Tests.Given_HelloWorld
{
public class When_GetMessage : WithFakes
{
private HelloWorld Subject => Subject<HelloWorld>();
public When_GetMessage()
{
The<IFoo>().Setup(x => x.GetFoo()).Returns("Hello");
With<IBar>(x => x.GetBar() == ", World!");
}
[Fact]
public void Should_invoke_IFoo_GetMessage()
{
Subject.GetMessage();
The<IFoo>().Verify(x => x.GetFoo());
}
[Fact]
public void Should_invoke_IBar_GetMessage()
{
Subject.GetMessage();
The<IBar>().Verify(x => x.GetBar(), Times.Once);
}
[Fact]
public void Should_return_a_concatenated_string_with_messages_from_IFoo_and_IBar()
{
Subject.GetMessage().ShouldEqual("Hello, World!");
}
}
}
using System;
using System.Linq.Expressions;
using Moq;
using Moq.AutoMock;
namespace ConductOfCode.Tests.Fakes
{
/// <summary>
/// Base class that adds auto mocking/faking to Xunit.
/// </summary>
public abstract class WithFakes : IDisposable
{
private readonly AutoMocker _mocker;
private object _subject;
protected WithFakes()
{
_mocker = new AutoMocker();
}
public void Dispose()
{
_subject = null;
}
/// <summary>
/// Gives access to the subject under specification.
/// On first access the spec tries to create an instance of the subject type by itself.
/// </summary>
/// <typeparam name="TSubject">The type of subject to create.</typeparam>
/// <returns>The subject of the specification.</returns>
protected TSubject Subject<TSubject>() where TSubject : class
{
if (_subject != null) return _subject as TSubject;
_subject = _mocker.CreateInstance<TSubject>();
return (TSubject)_subject;
}
/// <summary>
/// Creates a fake of the type specified by <typeparamref name="TInterfaceType" />.
/// This method reuses existing instances. If an instance of <typeparamref name="TInterfaceType" />
/// was already requested it's returned here. (You can say this is kind of a singleton behavior)
/// Besides that, you can obtain a reference to injected instances/fakes with this method.
/// </summary>
/// <typeparam name="TInterfaceType">The type to create a fake for. (Should be an interface or an abstract class)</typeparam>
/// <returns>
/// An instance implementing <typeparamref name="TInterfaceType" />.
/// </returns>
protected Mock<TInterfaceType> The<TInterfaceType>() where TInterfaceType : class
{
return _mocker.GetMock<TInterfaceType>();
}
/// <summary>
/// Configures the specification to use the specified instance for <typeparamref name="TInterfaceType" />.
/// </summary>
/// <typeparam name="TInterfaceType">The type to inject.</typeparam>
/// <param name="instance">The instance to inject.</param>
protected void With<TInterfaceType>(TInterfaceType instance)
{
_mocker.Use(instance);
}
/// <summary>
/// Configures the specification to use the specified mock for <typeparamref name="TInterfaceType" />.
/// </summary>
/// <typeparam name="TInterfaceType">The type to inject.</typeparam>
/// <param name="mock">The mock to inject.</param>
protected void With<TInterfaceType>(Mock<TInterfaceType> mock) where TInterfaceType : class
{
_mocker.Use(mock);
}
/// <summary>
/// Configures the specification to setup a mock with specified behavior for <typeparamref name="TInterfaceType" />.
/// </summary>
/// <typeparam name="TInterfaceType">The type to inject.</typeparam>
/// <param name="setup">The behavior to inject.</param>
protected void With<TInterfaceType>(Expression<Func<TInterfaceType, bool>> setup) where TInterfaceType : class
{
_mocker.Use(setup);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment