Skip to content

Commit

Permalink
Merge pull request #3 from hhoangnl/feature/arrange-specific-instance
Browse files Browse the repository at this point in the history
Added overloads to WithDependency<T> to accept self-created instances
  • Loading branch information
hhoangnl authored Oct 12, 2020
2 parents b43d7b1 + 69ac40b commit 0e7d783
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 14 deletions.
8 changes: 5 additions & 3 deletions FluentArrange.NSubstitute/FluentArrange.NSubstitute.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>8.0</LangVersion>
<Version>0.1.1-alpha</Version>
<Version>0.2.0-alpha</Version>
<Description>FluentArrange using NSubstitute as mocking framework.</Description>
<PackageProjectUrl>https://github.com/FluentArrange</PackageProjectUrl>
<PackageProjectUrl>https://github.com/hhoangnl/FluentArrange</PackageProjectUrl>
<RepositoryUrl>https://github.com/hhoangnl/FluentArrange</RepositoryUrl>
<PackageReleaseNotes>Refactored naming, added .Sut&lt;T&gt; method to get the sut directly, added .Dependency&lt;T&gt; to get the mocked dependencies</PackageReleaseNotes>
<PackageReleaseNotes>Added overloads to accept instances:
- WithDependency&lt;T&gt;(T)
- WithDependency&lt;T&gt;(T, Action&lt;T&gt;)</PackageReleaseNotes>
<PackageTags>AAA TDD mocking unit-testing nsubstitute</PackageTags>
<Authors>Huy Hoang</Authors>
<Copyright>Huy Hoang</Copyright>
Expand Down
41 changes: 40 additions & 1 deletion FluentArrange.Tests/FluentArrangeContextTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,44 @@ public void BuildSut_DependencyContainsInstance_BuiltSutShouldContainDependencyI
// Assert
result.AccountRepository.Should().Be(dependency);
}

[Fact]
public void WithDependency_Instance_DependenciesShouldContainInstance()
{
// Arrange
var dependencies = new Dictionary<Type, object>
{
{typeof(IAccountRepository), new AccountRepository()}
};

var sut = new FluentArrangeContext<AccountService>(dependencies);

var newInstance = new AccountRepository();

// Act
sut.WithDependency<IAccountRepository>(newInstance);

// Assert
sut.Dependencies[typeof(IAccountRepository)].Should().Be(newInstance);
}

[Fact]
public void WithDependency_Instance_TypeNotFound_ShouldThrowInvalidOperationException()
{
// Arrange
var dependencies = new Dictionary<Type, object>
{
{typeof(IAccountRepository), new AccountRepository()}
};

var sut = new FluentArrangeContext<AccountService>(dependencies);

// Act
Action act = () => sut.WithDependency<IFoo>(new Foo());

// Assert
act.Should().Throw<InvalidOperationException>()
.And.Message.Should().Be("No dependency found of type FluentArrange.Tests.TestClasses.IFoo");
}
}
}
}
9 changes: 9 additions & 0 deletions FluentArrange.Tests/TestClasses/Foo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) Huy Hoang. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

namespace FluentArrange.Tests.TestClasses
{
public class Foo : IFoo
{
}
}
8 changes: 5 additions & 3 deletions FluentArrange/FluentArrange.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>8.0</LangVersion>
<Version>0.1.1-alpha</Version>
<Version>0.2.0-alpha</Version>
<Description>Write clean Arrange code using Fluent syntax.</Description>
<PackageProjectUrl>https://github.com/FluentArrange</PackageProjectUrl>
<PackageProjectUrl>https://github.com/hhoangnl/FluentArrange</PackageProjectUrl>
<RepositoryUrl>https://github.com/hhoangnl/FluentArrange</RepositoryUrl>
<PackageReleaseNotes>Refactored naming, added .Sut&lt;T&gt; method to get the sut directly, added .Dependency&lt;T&gt; to get the mocked dependencies</PackageReleaseNotes>
<PackageReleaseNotes>Added overloads to accept instances:
- WithDependency&lt;T&gt;(T)
- WithDependency&lt;T&gt;(T, Action&lt;T&gt;)</PackageReleaseNotes>
<PackageTags>AAA TDD mocking unit-testing</PackageTags>
<Authors>Huy Hoang</Authors>
<Copyright>Huy Hoang</Copyright>
Expand Down
26 changes: 22 additions & 4 deletions FluentArrange/FluentArrangeContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,18 @@

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace FluentArrange
{
public class FluentArrangeContext<T>
where T : class
{
internal readonly IReadOnlyDictionary<Type, object> Dependencies;
internal readonly Dictionary<Type, object> Dependencies;

internal FluentArrangeContext(IDictionary<Type, object> dependencies)
internal FluentArrangeContext(Dictionary<Type, object> dependencies)
{
Dependencies = new ReadOnlyDictionary<Type, object>(dependencies);
Dependencies = new Dictionary<Type, object>(dependencies);
}

private T? _sut;
Expand All @@ -32,6 +31,25 @@ public FluentArrangeContext<T> WithDependency<T2>(Action<T2> configureDependency
return this;
}

public FluentArrangeContext<T> WithDependency<T2>(T2 instance) where T2 : class
{
_ = Dependency<T2>();

Dependencies[typeof(T2)] = instance;

return this;
}

public FluentArrangeContext<T> WithDependency<T2>(T2 instance, Action<T2> configureInstance) where T2 : class
{
_ = Dependency<T2>();

Dependencies[typeof(T2)] = instance;
configureInstance(instance);

return this;
}

public T2 Dependency<T2>() where T2 : class
{
if (Dependencies.TryGetValue(typeof(T2), out var value) && value is T2 dependency)
Expand Down
29 changes: 26 additions & 3 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ FluentArrange lets you write clean Arrange blocks in your unit tests when the co
| Package | Version | Description |
|-----------------------------|---------|-------------------------------------------------------------------------|
| `FluentArrange` | [![Nuget version](https://img.shields.io/nuget/v/fluentarrange)](https://www.nuget.org/packages/fluentarrange) | Core package
| `FluentArrange.NSubstitute` | [![Nuget version](https://img.shields.io/nuget/v/fluentarrange.nsubstitute)](https://www.nuget.org/packages/fluentarrange.nsubstitute) | When you use [NSubstitute](https://github.com/nsubstitute/NSubstitute) as the mocking framework
| `FluentArrange.NSubstitute` | [![Nuget version](https://img.shields.io/nuget/v/fluentarrange.nsubstitute)](https://www.nuget.org/packages/fluentarrange.nsubstitute) | When you use [NSubstitute](https://github.com/nsubstitute/NSubstitute) for mocking

## Auto-Mocking Ctor Dependencies
Consider the following example where we use NSubstitute to mock dependencies:
Expand Down Expand Up @@ -38,13 +38,36 @@ var sut = new ResetPasswordController(
mailService);
~~~

With FluentArrange, you can use Fluent API to achieve the exact same result as the code above:
With FluentArrange, you can use the Fluent API `WithDependency<T>` to achieve the exact same result as the code above:
~~~ C#
var sut = Arrange.Sut<ResetPasswordController>()
.WithDependency<IAccountService>(x => x.FindEmail("foo@foo.com").Returns(new Account("foo")))
.WithDependency<IMailService>(x => x.SendMail("foo@foo.com").Returns(true));
~~~

As you might have noticed, we did not need write arrange code for `IAuditService`, as that will be automatically created for you.
The only time you need to call `WithDependency<T>` is when you need to arrange the behavior of type `T`.

## Passing an instance instead
Sometimes, you may want to use a fake implementation rather than letting FluentArrange automatically create mocked instances.

In that case, you can provide an instance using `WithDependency<T>(T)`:

~~~ C#
var context = Arrange.Sut<ResetPasswordController>()
.WithDependency<IAccountService>(new InMemoryAccountService());
~~~

or `WithDependency<T>(T, Action<T>)` if you need to do more arranging:
~~~ C#
var context = Arrange.Sut<ResetPasswordController>()
.WithDependency<IAccountService>(new InMemoryAccountService(), d =>
{
d.AddAccount("foo", "foo@foo.com");
d.AddAccount("foobar", "foobar@foo.com");
});
~~~

## Asserting Dependencies
Suppose you need to assert that a dependency's method has been called.
Well, you simply arrange code with `Arrange.For<T>` instead of `Arrange.Sut<T>` to get a `FluentArrangeContext` object:
Expand Down Expand Up @@ -73,4 +96,4 @@ context.Sut.Reset("foo@foo.com");

// Assert
context.Dependency<IAccountService>().Received(1).FindEmail("foo@foo.com");
~~~
~~~

0 comments on commit 0e7d783

Please sign in to comment.