Last active
February 26, 2017 20:54
-
-
Save hlaueriksson/fceb24a6d9fb591519a5988be25dc191 to your computer and use it in GitHub Desktop.
2017-02-28-automocking-and-the-dependency-inversion-principle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!"; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using StructureMap; | |
namespace ConductOfCode.Core | |
{ | |
public class HelloWorldRegistry : Registry | |
{ | |
public HelloWorldRegistry() | |
{ | |
For<IHelloWorld>().Use<HelloWorld>(); | |
For<IFoo>().Use<Foo>(); | |
For<IBar>().Use<Bar>(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
}) | |
); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!"); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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