Skip to content

Commit

Permalink
Select a specific constructor (#16)
Browse files Browse the repository at this point in the history
Added support for picking a specific constructor for instantiation.
  • Loading branch information
hhoangnl authored Feb 18, 2022
1 parent b33b0c4 commit 31e9757
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 14 deletions.
28 changes: 19 additions & 9 deletions FluentArrange.Tests/ArrangeTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Huy Hoang. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

using System;
using System.Linq;
using FluentArrange.Tests.TestClasses;
using FluentAssertions;
using Xunit;
Expand All @@ -11,20 +11,30 @@ namespace FluentArrange.Tests
public class ArrangeTests
{
[Fact]
public void For_MultipleCtorsFound_ShouldThrowInvalidOperationException()
public void For_MultipleCtorsFound_ShouldPickFirst()
{
// Act
Action act = () => Arrange.For<MultipleCtor>(type => new object());
var sut = Arrange.For<MultipleCtor>(_ => new object());

// Assert
act.Should().Throw<InvalidOperationException>();
sut.Sut.CtorUsed.Should().Be(1);
}

[Fact]
public void For_PickSpecificCtor_ShouldUse()
{
// Act
var sut = Arrange.For<MultipleCtor>(_ => new Foo(), constructors => constructors.Last());

// Assert
sut.Sut.CtorUsed.Should().Be(2);
}

[Fact]
public void For_ParameterlessCtor_ShouldNotHaveAnyDependencies()
{
// Act
var result = Arrange.For<AccountRepository>(type => new object());
var result = Arrange.For<AccountRepository>(_ => new object());

// Assert
result.Dependencies.Should().BeEmpty();
Expand All @@ -37,7 +47,7 @@ public void For_CtorWithParameters_ShouldReturnFluentArrangeObjectWithDependency
var dependency = new AccountRepository();

// Act
var result = Arrange.For<AccountService>(type => dependency);
var result = Arrange.For<AccountService>(_ => dependency);

// Assert
result.Dependencies.Values.Should().SatisfyRespectively(first => first.Should().Be(dependency));
Expand All @@ -50,7 +60,7 @@ public void Sut_Func_ShouldReturnDependency()
var dependency = new AccountRepository();

// Act
var result = Arrange.Sut<AccountService>(type => dependency);
var result = Arrange.Sut<AccountService>(_ => dependency);

// Assert
result.AccountRepository.Should().Be(dependency);
Expand All @@ -63,7 +73,7 @@ public void Sut_Func_Action_ShouldReturnDependency()
var dependency = new AccountRepository();

// Act
var result = Arrange.Sut<AccountService>(type => dependency, action => { });
var result = Arrange.Sut<AccountService>(_ => dependency, action => { });

// Assert
result.AccountRepository.Should().Be(dependency);
Expand All @@ -77,7 +87,7 @@ public void Sut_Func_Action_ShouldInvokeAction()
var invoked = false;

// Act
_ = Arrange.Sut<AccountService>(type => dependency, action => invoked = true);
_ = Arrange.Sut<AccountService>(_ => dependency, action => invoked = true);

// Assert
invoked.Should().BeTrue();
Expand Down
4 changes: 4 additions & 0 deletions FluentArrange.Tests/TestClasses/MultipleCtor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ namespace FluentArrange.Tests.TestClasses
{
public class MultipleCtor
{
public int CtorUsed { get; }

public MultipleCtor()
{
CtorUsed = 1;
}

public MultipleCtor(IFoo foo)
{
CtorUsed = 2;
}
}
}
23 changes: 20 additions & 3 deletions FluentArrange/Arrange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,34 @@ namespace FluentArrange
{
public static class Arrange
{
/// <summary>
/// Construct a class of type {T} (using the first public constructor) and inject it with mocked dependencies.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="createMockType"></param>
/// <returns></returns>
public static FluentArrangeContext<T> For<T>(Func<Type, object> createMockType)
where T : class
{
return For<T>(createMockType, constructors => constructors.FirstOrDefault(c => c.IsPublic));
}

/// <summary>
/// Construct a class of type {T} and inject it with mocked dependencies.
/// </summary>
/// <typeparam name="T">Type of the concrete class</typeparam>
/// <param name="createMockType">The method to create mocked dependencies</param>
/// <param name="constructorSelector">Pick a specific constructor for instantiation</param>
/// <returns>An instance of {T}</returns>
public static FluentArrangeContext<T> For<T>(Func<Type, object> createMockType)
public static FluentArrangeContext<T> For<T>(Func<Type, object> createMockType, Func<IEnumerable<ConstructorInfo>, ConstructorInfo?> constructorSelector)
where T : class
{
var constructor = typeof(T).GetTypeInfo().DeclaredConstructors.Single();

var constructor = constructorSelector.Invoke(typeof(T).GetTypeInfo().DeclaredConstructors);
if (constructor == null)
{
throw new InvalidOperationException("No matching constructor found.");
}

var listOfDependencies = new Dictionary<Type, object>();

foreach (var p in constructor.GetParameters())
Expand Down
4 changes: 2 additions & 2 deletions FluentArrange/FluentArrange.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
<PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework>
<LangVersion>8.0</LangVersion>
<Version>0.10</Version>
<Version>0.11</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>Removed obsolete method</PackageReleaseNotes>
<PackageReleaseNotes>Added support for picking a specific constructor.</PackageReleaseNotes>
<PackageTags>AAA TDD mocking unit-testing</PackageTags>
<Authors>Huy Hoang</Authors>
<Copyright>Huy Hoang</Copyright>
Expand Down

0 comments on commit 31e9757

Please sign in to comment.