Skip to content

Commit

Permalink
Make available to .NET Core 3.1
Browse files Browse the repository at this point in the history
  • Loading branch information
cwinland committed May 31, 2022
1 parent 1169164 commit d1e480b
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 31 deletions.
4 changes: 2 additions & 2 deletions FastMoq.TestingExample/FastMoq.TestingExample.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net5.0;net6.0</TargetFrameworks>
<TargetFrameworks>netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
<Nullable>enable</Nullable>

<LangVersion>latest</LangVersion>
<IsPackable>false</IsPackable>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp90</s:String></wpf:ResourceDictionary>
4 changes: 2 additions & 2 deletions FastMoq.Tests/FastMoq.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net5.0;net6.0</TargetFrameworks>
<TargetFrameworks>netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
<Nullable>enable</Nullable>

<LangVersion>latest</LangVersion>
<IsPackable>false</IsPackable>
</PropertyGroup>

Expand Down
17 changes: 16 additions & 1 deletion FastMoq.Tests/MocksTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ public void FileSystem_ShouldBeValid()
Mocks.fileSystem.DriveInfo.Should().NotBeNull();
Mocks.fileSystem.FileStream.Should().NotBeNull();
Mocks.fileSystem.FileSystem.Should().NotBeNull();
Mocks.fileSystem.FileSystem.GetType().IsAssignableTo(typeof(IFileSystem)).Should().BeTrue();
typeof(IFileSystem).IsAssignableFrom(Mocks.fileSystem.FileSystem.GetType()).Should().BeTrue();
// Mocks.fileSystem.FileSystem.GetType().IsAssignableTo(typeof(IFileSystem)).Should().BeTrue();
Mocks.GetObject<IFileSystem>().Should().Be(Mocks.fileSystem.FileSystem);
Mocks.Strict = true;
Mocks.GetObject<IFileSystem>().Should().NotBe(Mocks.fileSystem.FileSystem);
Expand Down Expand Up @@ -391,6 +392,20 @@ private void CheckBestConstructor(object data, bool expected = true)
isValid.Should().Be(expected);
}

[Fact]
public void FindConstructor_Missing_ShouldThrow()
{
Action a = () => Mocks.FindConstructor(typeof(TestClassMany), Mocks.GetObject<IFileSystem>());
a.Should().Throw<NotImplementedException>();
}

[Fact]
public void FindConstructor_Exact()
{
var m = Mocks.FindConstructor(typeof(TestClassMany), 4, "");
m.Should().NotBeNull();
}

[Fact]
public void IsValidConstructor()
{
Expand Down
40 changes: 40 additions & 0 deletions FastMoq.Tests/NestedClassTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;

namespace FastMoq.Tests
{
public class NestedClassTests
{
private Mocks mocks;

public NestedClassTests()
{
mocks = new Mocks();
}

[Fact]
public void GetTypeFromInterface()
{
typeof(INestedTestClassBase).IsAssignableFrom(typeof(INestedTestClass)).Should().BeTrue();
typeof(INestedTestClassBase).IsAssignableFrom(typeof(NestedTestClass)).Should().BeTrue();

typeof(INestedTestClass).IsAssignableFrom(typeof(INestedTestClass)).Should().BeTrue();
typeof(INestedTestClass).IsAssignableFrom(typeof(NestedTestClass)).Should().BeTrue();

var r = mocks.GetTypeFromInterface<INestedTestClassBase>();
var s = mocks.GetTypeFromInterface<INestedTestClass>();

r.InstanceType.Should().Be(typeof(NestedTestClassBase));
s.InstanceType.Should().Be(typeof(NestedTestClass));

typeof(INestedTestClassBase).IsAssignableFrom(s.InstanceType).Should().BeTrue();
typeof(INestedTestClassBase).IsAssignableFrom(r.InstanceType).Should().BeTrue();

typeof(INestedTestClass).IsAssignableFrom(s.InstanceType).Should().BeTrue();
typeof(INestedTestClass).IsAssignableFrom(r.InstanceType).Should().BeFalse();
}
}
}
19 changes: 19 additions & 0 deletions FastMoq.Tests/NestedTestClass.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace FastMoq.Tests
{
public class NestedTestClass : INestedTestClass
{
}

public class NestedTestClassBase : INestedTestClassBase
{
}

public interface INestedTestClass : INestedTestClassBase
{
}

public interface INestedTestClassBase
{
}

}
6 changes: 3 additions & 3 deletions FastMoq/FastMoq.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net5.0;net6.0</TargetFrameworks>
<TargetFrameworks>netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
Expand All @@ -11,11 +11,11 @@
<Company>$(Authors)</Company>
<Copyright>Copyright(c) 2022 Christopher Winland</Copyright>
<PackageId>$(AssemblyName)</PackageId>
<Description>Easy and fast extension of Moq (from moqthis) Mocking framework for super easy mocking of classes.</Description>
<Description>Easy and fast extension of (from moqthis), mocking framework, for mocking and auto injection of classes.</Description>
<PackageProjectUrl>https://github.com/cwinland/FastMoq</PackageProjectUrl>
<RepositoryUrl>https://github.com/cwinland/FastMoq</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>Easy; fast; extension;Moq;moqthis;Mocking;framework;mocking;class.</PackageTags>
<PackageTags>Easy;fast;injection;inject;mock;extension;Moq;moqthis;framework;mocking;class</PackageTags>
<PackageLicenseFile>license.txt</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<IsPackable>true</IsPackable>
Expand Down
22 changes: 11 additions & 11 deletions FastMoq/Mocks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,14 +324,11 @@ public Mock<T> Initialize<T>(Action<Mock<T>> action) where T : class
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
public bool RemoveMock<T>(Mock<T> mock) where T : class
{
var mockModel = mockCollection.FirstOrDefault(x => x.Type == typeof(T) && x.Mock == mock);

var mockModel = GetMockModel(typeof(T), mock);
return mockModel != null && mockCollection.Remove(mockModel);
}

internal int GetMockModelIndexOf(Type type) => mockCollection.IndexOf(GetMockModel(type));
internal MockModel GetMockModel(Type type, Mock? mock = null) => mockCollection.FirstOrDefault(x => x.Type == type && (x.Mock == mock || mock == null));
internal MockModel GetMockModel<T>(Mock<T>? mock = null) where T : class => GetMockModel(typeof(T), mock);
internal MockModel? GetMockModel(Type type, Mock? mock = null) => mockCollection.FirstOrDefault(x => x.Type == type && (x.Mock == mock || mock == null));

/// <summary>
/// Add specified Mock. Internal API only.
Expand Down Expand Up @@ -360,7 +357,7 @@ internal Mock AddMock(Mock mock, Type type, bool overwrite)
ThrowAlreadyExists(mock.GetType());
}

var mockModel = GetMockModel(type);
var mockModel = GetMockModel(type) ?? new MockModel(type, mock);
mockModel.Mock = mock;
return GetMock(type);
}
Expand All @@ -371,7 +368,7 @@ internal Mock AddMock(Mock mock, Type type, bool overwrite)
}

/// <summary>
/// Finds the constructor matching args EXACTLY.
/// Finds the constructor matching args EXACTLY with the same sequence and type.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="args">The arguments.</param>
Expand All @@ -382,15 +379,18 @@ internal Mock AddMock(Mock mock, Type type, bool overwrite)
Dictionary<ConstructorInfo, List<object?>> allConstructors = GetConstructors(type, args);

List<KeyValuePair<ConstructorInfo, List<object?>>> constructors = allConstructors
.Where(x => x.Value.Select(z => z?.GetType()).SequenceEqual(args.Select(y => y?.GetType()))).ToList();
.Where(x => x.Value
.Select(z => z?.GetType())
.SequenceEqual(args.Select(y => y?.GetType())))
.ToList();

return !constructors.Any()
? throw new NotImplementedException("Unable to find the constructor.")
: constructors.First();
}

/// <summary>
/// Finds the constructor.
/// Finds the constructor and chooses the one with the parameters, if it exists.
/// </summary>
/// <param name="bestGuess">if set to <c>true</c> [best guess].</param>
/// <param name="type">The type.</param>
Expand Down Expand Up @@ -457,7 +457,7 @@ internal InstanceModel GetTypeFromInterface<T>() where T : class
List<Type> possibleTypes = types.Where(type =>
type.GetInterfaces().Contains(tType) &&
interfaces.All(iType => type != iType) &&
!interfaces.Any(type.IsAssignableTo)
!interfaces.Any(iType => iType.IsAssignableFrom(type))
).ToList();

return new InstanceModel(possibleTypes.Count > 1 ? throw new AmbiguousImplementationException() :
Expand Down Expand Up @@ -490,7 +490,7 @@ internal static bool IsValidConstructor(ConstructorInfo info, params object?[] i
{
var paramType = paramList[i].ParameterType;
var instanceType = instanceParameterValues[i]?.GetType();
isValid &= (instanceType == null && paramType.IsNullableType()) || (instanceType != null && instanceType.IsAssignableTo(paramType));
isValid &= (instanceType == null && paramType.IsNullableType()) || (instanceType != null && paramType.IsAssignableFrom(instanceType));
}

return isValid;
Expand Down
41 changes: 29 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# FastMoq

Easy and fast extension of [Moq](https://github.com/Moq) Mocking framework for mocking and auto injection of classes.
Easy and fast extension of [Moq](https://github.com/Moq), mocking framework, for mocking and auto injection of classes.

## Features

Expand All @@ -11,6 +11,7 @@ Easy and fast extension of [Moq](https://github.com/Moq) Mocking framework for m

## Targets

- .NET Core 3.1
- .NET 5
- .NET 6

Expand All @@ -19,14 +20,14 @@ Easy and fast extension of [Moq](https://github.com/Moq) Mocking framework for m
The following constructor parameters allow customization on the testing classes.

```cs
Action<Mocks>? setupMocksAction
Action<Mocks> setupMocksAction
Func<TComponent> createComponentAction
Action<TComponent?>? createdComponentAction
```

## Examples

### Class being tested
### Example Test Class

Testing this class will auto inject IFileSystem.

Expand All @@ -41,7 +42,9 @@ public class TestClassNormal : ITestClassNormal
}
```

### Fast Start
### Fast Start Testing

TestClassNormal is created and injects IFileSystem.

```cs
public class TestClassNormalTestsDefaultBase : TestBase<TestClassNormal>
Expand All @@ -59,6 +62,8 @@ public class TestClassNormalTestsDefaultBase : TestBase<TestClassNormal>

### Pre-Test Setup

TestClassNormal is created and injects IFileSystem. SetupMocksAction creates and configures the Mock IFileSystem before the component is created.

```cs
public class TestClassNormalTestsSetupBase : TestBase<TestClassNormal>
{
Expand All @@ -85,6 +90,8 @@ public class TestClassNormalTestsSetupBase : TestBase<TestClassNormal>

### Custom Setup, Creation, and Post Create routines

TestClassNormal is created and injects IFileSystem. SetupMocksAction creates and configures the Mock IFileSystem before the component is created. Once created, the CreatedComponentAction subscribes to an event on the component.

```cs
public class TestClassNormalTestsFull : TestBase<TestClassNormal>
{
Expand Down Expand Up @@ -120,31 +127,41 @@ public class TestClassNormalTestsFull : TestBase<TestClassNormal>
}
```

### Interface Type Map
### Auto Injection

Auto injection allows creation of components with parameterized interfaces. If an override for creating the component is not specified, the component will be created will the default Mock Objects.

A map is available to decide which class is injected for the given interface.
#### Auto Injection with instance parameters

#### Two classes
Additionally, the creation can be overwritten and provided with instances of the parameters. CreateInstance will automatically match the correct constructor to the parameters given to CreateInstance.

```cs
private static TestClassNormal CreateComponentAction() => Mocks.CreateInstance(new MockFileSystem()); // CreateInstance matches the parameters and types with the Component constructor.
```

#### Interface Type Map

When multiple classes derive from the same interface, the Interface Type Map can map with class to use for the given injected interface.

##### Example of two classes inheriting the same interface

```cs
public class TestClassDouble1 : ITestClassDouble {}
public class TestClassDouble2 : ITestClassDouble {}
```

#### Mapping
##### Mapping

This code maps ITestClassDouble to TestClassDouble1 when testing a component with ITestClassDouble.

```cs
Mocks.AddType<ITestClassDouble, TestClassDouble1>();
```

### Auto injection

Auto injection allows creation of components by selecting the constructor with the matching parameter types and data.
The map also accepts parameters to tell it how to create the instance.

```cs
private static TestClassNormal CreateComponentAction() => Mocks.CreateInstance(new MockFileSystem()); // CreateInstance matches the parameters and types with the Component constructor.
Mocks.AddType<ITestClassDouble, TestClassDouble1>(() => new TestClassDouble());
```

## [License - MIT](./License)

0 comments on commit d1e480b

Please sign in to comment.