Skip to content

Commit

Permalink
Merge pull request #4 from hhoangnl/feature/arrange-with-dependency-n…
Browse files Browse the repository at this point in the history
…ew-overload

Add WithDependency<T, T2>(T2, Action<T2>) overload
  • Loading branch information
hhoangnl authored Oct 13, 2020
2 parents 0e7d783 + 24f33d8 commit 5897f64
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 35 deletions.
7 changes: 3 additions & 4 deletions FluentArrange.NSubstitute/FluentArrange.NSubstitute.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>8.0</LangVersion>
<Version>0.2.0-alpha</Version>
<Version>0.3.0-alpha</Version>
<Description>FluentArrange using NSubstitute as mocking framework.</Description>
<PackageProjectUrl>https://github.com/hhoangnl/FluentArrange</PackageProjectUrl>
<RepositoryUrl>https://github.com/hhoangnl/FluentArrange</RepositoryUrl>
<PackageReleaseNotes>Added overloads to accept instances:
- WithDependency&lt;T&gt;(T)
- WithDependency&lt;T&gt;(T, Action&lt;T&gt;)</PackageReleaseNotes>
<PackageReleaseNotes>Added overload to configure and call T2-specific methods:
- WithDependency&lt;T, T2&gt;(T2, Action&lt;T2&gt;)</PackageReleaseNotes>
<PackageTags>AAA TDD mocking unit-testing nsubstitute</PackageTags>
<Authors>Huy Hoang</Authors>
<Copyright>Huy Hoang</Copyright>
Expand Down
88 changes: 64 additions & 24 deletions FluentArrange.Tests/FluentArrangeContextTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,39 @@ namespace FluentArrange.Tests
public class FluentArrangeContextTests
{
[Fact]
public void WithDependency_DependencyTypeNotFound_ShouldNotCallConfigureDependency()
public void WithDependency_TypeNotFound_ShouldNotInvokeAction()
{
// Arrange
var called = false;
var invoked = false;
var sut = new FluentArrangeContext<object>(new Dictionary<Type, object>());

// Act
sut.WithDependency<IAccountRepository>(e => called = true);
sut.WithDependency<IAccountRepository>(e => invoked = true);

// Assert
called.Should().BeFalse();
invoked.Should().BeFalse();
}

[Fact]
public void WithDependency_DependencyTypeFound_ShouldInvokeConfigureDependency()
public void WithDependency_TypeFound_ShouldInvokeAction()
{
// Arrange
var called = false;
var invoked = false;
var dependencies = new Dictionary<Type, object>
{
{typeof(IAccountRepository), new AccountRepository()}
};
var sut = new FluentArrangeContext<AccountService>(dependencies);

// Act
sut.WithDependency<IAccountRepository>(e => called = true);
sut.WithDependency<IAccountRepository>(e => invoked = true);

// Assert
called.Should().BeTrue();
invoked.Should().BeTrue();
}

[Fact]
public void WithDependency_ShouldReturnReferenceToSut()
public void WithDependency_Type_ShouldReturnReferenceToSut()
{
// Arrange
var sut = new FluentArrangeContext<AccountService>(new Dictionary<Type, object>());
Expand All @@ -57,27 +57,27 @@ public void WithDependency_ShouldReturnReferenceToSut()
}

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

var sut = new FluentArrangeContext<AccountService>(dependencies)
.WithDependency<IAccountRepository>(e => { });
var sut = new FluentArrangeContext<AccountService>(dependencies);

var newInstance = new AccountRepository();

// Act
var result = sut.BuildSut();
sut.WithDependency<IAccountRepository>(newInstance);

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

[Fact]
public void WithDependency_Instance_DependenciesShouldContainInstance()
public void WithDependency_T_InstanceTypeNotFound_ShouldThrowInvalidOperationException()
{
// Arrange
var dependencies = new Dictionary<Type, object>
Expand All @@ -87,17 +87,36 @@ public void WithDependency_Instance_DependenciesShouldContainInstance()

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

var newInstance = new AccountRepository();
// 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");
}

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

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

var invoked = false;

// Act
sut.WithDependency<IAccountRepository>(newInstance);
sut.WithDependency<IAccountRepository, AccountRepository>(new AccountRepository(), repository => invoked = true);

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

[Fact]
public void WithDependency_Instance_TypeNotFound_ShouldThrowInvalidOperationException()
public void WithDependency_T2_T3_InstanceTypeFound_DependenciesShouldContainInstance()
{
// Arrange
var dependencies = new Dictionary<Type, object>
Expand All @@ -107,12 +126,33 @@ public void WithDependency_Instance_TypeNotFound_ShouldThrowInvalidOperationExce

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

var instance = new AccountRepository();

// Act
Action act = () => sut.WithDependency<IFoo>(new Foo());
sut.WithDependency<IAccountRepository, AccountRepository>(instance, repository => { });

// Assert
act.Should().Throw<InvalidOperationException>()
.And.Message.Should().Be("No dependency found of type FluentArrange.Tests.TestClasses.IFoo");
sut.Dependencies[typeof(IAccountRepository)].Should().Be(instance);
}

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

var sut = new FluentArrangeContext<AccountService>(dependencies)
.WithDependency<IAccountRepository>(e => { });

// Act
var result = sut.BuildSut();

// Assert
result.AccountRepository.Should().Be(dependency);
}
}
}
8 changes: 4 additions & 4 deletions FluentArrange/FluentArrange.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>8.0</LangVersion>
<Version>0.2.0-alpha</Version>
<Version>0.3.0-alpha</Version>
<Description>Write clean Arrange code using Fluent syntax.</Description>
<PackageProjectUrl>https://github.com/hhoangnl/FluentArrange</PackageProjectUrl>
<RepositoryUrl>https://github.com/hhoangnl/FluentArrange</RepositoryUrl>
<PackageReleaseNotes>Added overloads to accept instances:
- WithDependency&lt;T&gt;(T)
- WithDependency&lt;T&gt;(T, Action&lt;T&gt;)</PackageReleaseNotes>
<PackageReleaseNotes>Added overload to configure and call T2-specific methods:
- WithDependency&lt;T, T2&gt;(T2, Action&lt;T2&gt;)
</PackageReleaseNotes>
<PackageTags>AAA TDD mocking unit-testing</PackageTags>
<Authors>Huy Hoang</Authors>
<Copyright>Huy Hoang</Copyright>
Expand Down
21 changes: 18 additions & 3 deletions FluentArrange/FluentArrangeContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ internal FluentArrangeContext(Dictionary<Type, object> dependencies)

public T Sut => _sut ??= BuildSut();

public FluentArrangeContext<T> WithDependency<T2>(Action<T2> configureDependency) where T2 : class
public FluentArrangeContext<T> WithDependency<T2>(Action<T2> configureDependency)
where T2 : class
{
if (Dependencies.TryGetValue(typeof(T2), out var value) && value is T2 dependency)
{
Expand All @@ -31,7 +32,8 @@ public FluentArrangeContext<T> WithDependency<T2>(Action<T2> configureDependency
return this;
}

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

Expand All @@ -40,7 +42,20 @@ public FluentArrangeContext<T> WithDependency<T2>(T2 instance) where T2 : class
return this;
}

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

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

return this;
}

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

Expand Down
9 changes: 9 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ var context = Arrange.Sut<ResetPasswordController>()
});
~~~

or `WithDependency<T, T2>(T2, Action<T2>)` if you need to call `T2`-specific methods:
~~~ C#
var context = Arrange.Sut<ResetPasswordController>()
.WithDependency<IAccountService, InMemoryAccountService>(new InMemoryAccountService(), d =>
{
d.AddTestAccounts();
});
~~~

## 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

0 comments on commit 5897f64

Please sign in to comment.