From d1e480b2710db03c7b90efe9fc86bbfb42990750 Mon Sep 17 00:00:00 2001 From: Chris Winland Date: Tue, 31 May 2022 09:25:44 -0400 Subject: [PATCH] Make available to .NET Core 3.1 --- .../FastMoq.TestingExample.csproj | 4 +- .../FastMoq.TestingExample.csproj.DotSettings | 2 + FastMoq.Tests/FastMoq.Tests.csproj | 4 +- FastMoq.Tests/MocksTests.cs | 17 +++++++- FastMoq.Tests/NestedClassTests.cs | 40 ++++++++++++++++++ FastMoq.Tests/NestedTestClass.cs | 19 +++++++++ FastMoq/FastMoq.csproj | 6 +-- FastMoq/Mocks.cs | 22 +++++----- README.md | 41 +++++++++++++------ 9 files changed, 124 insertions(+), 31 deletions(-) create mode 100644 FastMoq.TestingExample/FastMoq.TestingExample.csproj.DotSettings create mode 100644 FastMoq.Tests/NestedClassTests.cs create mode 100644 FastMoq.Tests/NestedTestClass.cs diff --git a/FastMoq.TestingExample/FastMoq.TestingExample.csproj b/FastMoq.TestingExample/FastMoq.TestingExample.csproj index 7a33945..8d6c474 100644 --- a/FastMoq.TestingExample/FastMoq.TestingExample.csproj +++ b/FastMoq.TestingExample/FastMoq.TestingExample.csproj @@ -1,9 +1,9 @@ - net5.0;net6.0 + netcoreapp3.1;net5.0;net6.0 enable - + latest false diff --git a/FastMoq.TestingExample/FastMoq.TestingExample.csproj.DotSettings b/FastMoq.TestingExample/FastMoq.TestingExample.csproj.DotSettings new file mode 100644 index 0000000..6162834 --- /dev/null +++ b/FastMoq.TestingExample/FastMoq.TestingExample.csproj.DotSettings @@ -0,0 +1,2 @@ + + CSharp90 \ No newline at end of file diff --git a/FastMoq.Tests/FastMoq.Tests.csproj b/FastMoq.Tests/FastMoq.Tests.csproj index 0c5a69a..f8f435d 100644 --- a/FastMoq.Tests/FastMoq.Tests.csproj +++ b/FastMoq.Tests/FastMoq.Tests.csproj @@ -1,9 +1,9 @@ - net5.0;net6.0 + netcoreapp3.1;net5.0;net6.0 enable - + latest false diff --git a/FastMoq.Tests/MocksTests.cs b/FastMoq.Tests/MocksTests.cs index ea3ca7b..4b37fb9 100644 --- a/FastMoq.Tests/MocksTests.cs +++ b/FastMoq.Tests/MocksTests.cs @@ -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().Should().Be(Mocks.fileSystem.FileSystem); Mocks.Strict = true; Mocks.GetObject().Should().NotBe(Mocks.fileSystem.FileSystem); @@ -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()); + a.Should().Throw(); + } + + [Fact] + public void FindConstructor_Exact() + { + var m = Mocks.FindConstructor(typeof(TestClassMany), 4, ""); + m.Should().NotBeNull(); + } + [Fact] public void IsValidConstructor() { diff --git a/FastMoq.Tests/NestedClassTests.cs b/FastMoq.Tests/NestedClassTests.cs new file mode 100644 index 0000000..eb7fb82 --- /dev/null +++ b/FastMoq.Tests/NestedClassTests.cs @@ -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(); + var s = mocks.GetTypeFromInterface(); + + 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(); + } + } +} diff --git a/FastMoq.Tests/NestedTestClass.cs b/FastMoq.Tests/NestedTestClass.cs new file mode 100644 index 0000000..26ef92f --- /dev/null +++ b/FastMoq.Tests/NestedTestClass.cs @@ -0,0 +1,19 @@ +namespace FastMoq.Tests +{ + public class NestedTestClass : INestedTestClass + { + } + + public class NestedTestClassBase : INestedTestClassBase + { + } + + public interface INestedTestClass : INestedTestClassBase + { + } + + public interface INestedTestClassBase + { + } + +} diff --git a/FastMoq/FastMoq.csproj b/FastMoq/FastMoq.csproj index 5694eda..cc5f642 100644 --- a/FastMoq/FastMoq.csproj +++ b/FastMoq/FastMoq.csproj @@ -1,7 +1,7 @@  - net5.0;net6.0 + netcoreapp3.1;net5.0;net6.0 enable latest enable @@ -11,11 +11,11 @@ $(Authors) Copyright(c) 2022 Christopher Winland $(AssemblyName) - Easy and fast extension of Moq (from moqthis) Mocking framework for super easy mocking of classes. + Easy and fast extension of (from moqthis), mocking framework, for mocking and auto injection of classes. https://github.com/cwinland/FastMoq https://github.com/cwinland/FastMoq git - Easy; fast; extension;Moq;moqthis;Mocking;framework;mocking;class. + Easy;fast;injection;inject;mock;extension;Moq;moqthis;framework;mocking;class license.txt README.md true diff --git a/FastMoq/Mocks.cs b/FastMoq/Mocks.cs index d5ff8ba..86441f6 100644 --- a/FastMoq/Mocks.cs +++ b/FastMoq/Mocks.cs @@ -324,14 +324,11 @@ public Mock Initialize(Action> action) where T : class /// true if XXXX, false otherwise. public bool RemoveMock(Mock 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(Mock? 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)); /// /// Add specified Mock. Internal API only. @@ -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); } @@ -371,7 +368,7 @@ internal Mock AddMock(Mock mock, Type type, bool overwrite) } /// - /// Finds the constructor matching args EXACTLY. + /// Finds the constructor matching args EXACTLY with the same sequence and type. /// /// The type. /// The arguments. @@ -382,7 +379,10 @@ internal Mock AddMock(Mock mock, Type type, bool overwrite) Dictionary> allConstructors = GetConstructors(type, args); List>> 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.") @@ -390,7 +390,7 @@ internal Mock AddMock(Mock mock, Type type, bool overwrite) } /// - /// Finds the constructor. + /// Finds the constructor and chooses the one with the parameters, if it exists. /// /// if set to true [best guess]. /// The type. @@ -457,7 +457,7 @@ internal InstanceModel GetTypeFromInterface() where T : class List 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() : @@ -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; diff --git a/README.md b/README.md index ec50410..bd6d1ca 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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 @@ -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? setupMocksAction +Action setupMocksAction Func createComponentAction Action? createdComponentAction ``` ## Examples -### Class being tested +### Example Test Class Testing this class will auto inject IFileSystem. @@ -41,7 +42,9 @@ public class TestClassNormal : ITestClassNormal } ``` -### Fast Start +### Fast Start Testing + +TestClassNormal is created and injects IFileSystem. ```cs public class TestClassNormalTestsDefaultBase : TestBase @@ -59,6 +62,8 @@ public class TestClassNormalTestsDefaultBase : TestBase ### 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 { @@ -85,6 +90,8 @@ public class TestClassNormalTestsSetupBase : TestBase ### 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 { @@ -120,18 +127,30 @@ public class TestClassNormalTestsFull : TestBase } ``` -### 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. @@ -139,12 +158,10 @@ This code maps ITestClassDouble to TestClassDouble1 when testing a component wit Mocks.AddType(); ``` -### 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(() => new TestClassDouble()); ``` ## [License - MIT](./License)