Giter VIP home page Giter VIP logo

moq.automocker's Introduction

Moq.AutoMock Continuous NuGet Status

An automocking container for Moq. Use this if you're invested in your IoC container and want to decouple your unit tests from changes to their constructor arguments.

Usage

Simplest usage is to build an instance that you can unit test.

var mocker = new AutoMocker();
var car = mocker.CreateInstance<Car>();

car.DriveTrain.ShouldNotBeNull();
car.DriveTrain.ShouldImplement<IDriveTrain>();
Mock<IDriveTrain> mock = Mock.Get(car.DriveTrain);

If you have a special instance that you need to use, you can register it with .Use(...). This is very similar to registrations in a regular IoC container (i.e. For<IService>().Use(x) in StructureMap).

var mocker = new AutoMocker();

mocker.Use<IDriveTrain>(new DriveTrain());
// OR, setup a Mock
mocker.Use<IDriveTrain>(x => x.Shaft.Length == 5);

var car = mocker.CreateInstance<Car>();

Extracting Mocks

At some point you might need to get to a mock that was auto-generated. For this, use the .Get<>() or .GetMock<>() methods.

var mocker = new AutoMocker();

// Let's say you have a setup that needs verifying
mocker.Use<IDriveTrain>(x => x.Accelerate(42) == true);

var car = mocker.CreateInstance<Car>();
car.Accelerate(42);

// Then extract & verify
var driveTrainMock = mocker.GetMock<IDriveTrain>();
driveTrainMock.VerifyAll();

Alternately, there's an even faster way to verify all mocks in the container:

var mocker = new AutoMocker();
mocker.Use<IDriveTrain>(x => x.Accelerate(42) == true);

var car = mocker.CreateInstance<Car>();
car.Accelerate(42);

// This method verifies all mocks in the container
mocker.VerifyAll();

moq.automocker's People

Contributors

adamhewitt627 avatar artem-chet avatar ascott18 avatar benjaminmichaelis avatar braincrumbz avatar chrissimmons avatar danielcweber avatar dependabot[bot] avatar eddex avatar github-actions[bot] avatar ian1971 avatar idzmitry avatar jeme avatar johnrayner avatar kaylanimis avatar keboo avatar lasrol avatar robrich avatar simoncropp avatar skobovm avatar tkellogg avatar torbenrahbekkoch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

moq.automocker's Issues

How can I set custom DefaultValueProvider?

When initializing AutoMocker I can set DefaultValue behavior, but I cannot find the way to set my custom default value provider to be used by every mock instance.

Is it possible?

AutoMocker as a custom IServiceProvider?

Hello,

Would it be possible to add support for returning a IServiceProvider with all the dependencies automocked except for the ones that were passed in?

Background

In the Startup.cs class it is possible to return IServiceProvider from the Configure(IServiceCollection services) method.

I figured that it would be really useful to be able to use the TestServer for testing controller endpoints while not needing to worry about setting up mocks.

In a testing scenario a subclass of Startup could be used, that would override a method that ConfigureServices calls and then return IServiceProvider that is built by AutoMocker().

Maybe something like this

public class Startup
{
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(options => { })
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);   
         return Configure(services);
    }

    public IServiceProvider virtual Configure(IServiceCollection services)
    {
         <non test DI setups>
        return services.BuildServiceProvider();
    }    
}

public class TestStartup
{
    public AutoMocker Mocker {get; set;}

    public IServiceProvider override Configure(IServiceCollection services)
    {
        Mocker.AddServices(services);
        return Mocker.BuilsServiceProvider();
    }
}


public class TestClass
{
    [Fact]
    public async Task Test1()
    {
     // setup all the mocks that the controller is supposed get  
      var mocker = new AutoMocker();
       // mocker.Use(....)
      TestStartup.Mocker = mocker;
       // build a test server with mocks injected
       var server = new TestServer(new WebHostBuilder()
                .UseStartup<TestStartup>());
       var httpClient = server.CreateClient();

       var response = await httpClient.GetAsync("/values");
    }
}

Inspired by these posts:
Adding custom IoC
https://asp.net-hacker.rocks/2017/05/08/add-custom-ioc-in-aspnetcore.html

Integration testing mock dependencies:
https://automationrhapsody.com/net-core-integration-testing-mock-dependencies/

Maybe there's already a solution for this?

What I tried

I actually tried to build my own solution like this

public override IServiceProvider Configure(IServiceCollection services)
{
     foreach (var service in services)
     {
         if (service.ImplementationInstance!= null)
              Mocker.Use(service.ServiceType, service.ImplementationInstance);
      }
     return new MockServiceProvider(Mocker, ServiceCollection);
}

public class MockServiceProvider : IServiceProvider
{
    private readonly AutoMocker _autoMocker;

    public MockServiceProvider(AutoMocker autoMocker)
    {
        _autoMocker = autoMocker;
    }

    public object GetService(Type serviceType)
    {
        return _autoMocker.Get(serviceType);
    }
}

But I get an error due to not being able to create a proxy for ILogger.

Castle.DynamicProxy.Generators.GeneratorException : Can not create proxy for type Microsoft.Extensions.Logging.ILogger`1[[Microsoft.AspNetCore.Hosting.Internal.WebHost, Microsoft.AspNetCore.Hosting, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]] because type Microsoft.AspNetCore.Hosting.Internal.WebHost is not accessible.

I do realize that this error could not be fixable by any Moq implementation, but I don't know that well how the Microsoft DI framework works and maybe it is.

Good day!

Add preview nuget packages.

Once we get the CI system setup I would recommend the following.

  • Mark the master branch as protected so PRs are required into it.
  • Setup AppVeyor to publish all successful merges to master as a preview nuget package.
  • Create a new release branch and mark it as protected.
  • Setup AppVeyor to publish non-preview nuget packages on all successful merges to the release branch.

GetMock<T>() != GetMock(Type t) for Interfaces

We are trying to register mocks for all interfaces when using the .net Core Test Host. We are using reflection to make this easier.

(sudo code below)
var types = GetAssemblywithInterfaces().Types;
foreeach( Type t in types)
servicecollection.Register(mocker.GetMock(t).Object);
^ this throws exceptions as t is an interface and not a class.

This does not work where as if we individual register each interface explicitly via
servicecollection.Register(mocker.GetMock().Object)
it works as expected

It seems there is a generic type constrainton GetMock Where T : Class
https://github.com/moq/Moq.AutoMocker/blob/master/Moq.AutoMock/AutoMocker.cs#L263

This is not equivalent to
https://github.com/moq/Moq.AutoMocker/blob/master/Moq.AutoMock/AutoMocker.cs#L274

from the microsoft documentation
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters
It seems where T : class restricts reference types not specifically "class" objects

defect? or should we not be doing our workflow

Support for nullable value types

When using nullable value types like int?, the verification has to be written in the form of autoMocker.GetMock<IService>().Verify<int?>(). As far as I see, this is due to the generic constraint where TResult : struct in public void Verify<T, TResult>(Expression<Func<T, TResult>> expression, Func<Times> times).

It would be nice to write it more concisely: autoMocker.Verify<IService, int?>(). Do you see any change for that?

CreateSelfMock has some sharp edges

In trying to use some SelfMocks for some things, I've ran into a couple different sharp edges.

1. There's no way to specify CallBase = true as a direct parameter to CreateSelfMock. Instead, I have to either configure the whole AutoMocker instance this way via its constructor, or I have to do the following:

var service = Mocker.CreateSelfMock<FooService>();
var mock = Mock.Get(service);
mock.CallBase = true;

This pattern is just a little ugly - it'd be nice to have an additional bool parameter: CreateSelfMock<FooService>(usePrivate: false, callBase: true). Maybe also throw in an optional parameters for MockBehavior as well?

2. Registering self mocks that have an interface back into the Mocker is hard.

The following doesn't work, but intuitively feels like it should:

interface IFooService { int Foo() }
class FooService : IFooService { 
	public FooService(ISomeDependency dep1, IOtherDependency dep2) {}
	virtual int Foo() => 42; 
}

var service = Mocker.CreateSelfMock<FooService>();
Mocker.Use<IFooService>(service);
Mocker.Setup<IFooService, int>(s => s.Foo()).Returns(24);

This throws with

  Message: 
System.ArgumentException : IFooService does not resolve to a Mock

  Stack Trace: 
AutoMocker.GetOrMakeMockFor(Type type)
AutoMocker.Setup[TReturn,TService](Func`2 returnValue)
AutoMocker.Setup[TService,TReturn](Expression`1 setup)

The same goes for using the concrete type without an interface - the following fails with the same exception.

var service = Mocker.CreateSelfMock<FooService>();
Mocker.Use<FooService>(service);
Mocker.Setup<FooService, int>(s => s.Foo()).Returns(24);

Instead, to make this work, one has to do this:

// Via Interface
var service = Mocker.CreateSelfMock<FooService>();
Mocker.Use<IFooService>(Mock.Get(service).As<IFooService>());
Mocker.Setup<IFooService, int>(s => s.Foo()).Returns(24);

// Via concrete class:
var service = Mocker.CreateSelfMock<FooService>();
Mocker.Use<FooService>(Mock.Get(service));
Mocker.Setup<FooService, int>(s => s.Foo()).Returns(24);

Would it be possible for Mocker.Use (the overloads that aren't already accepting a Mock<>) to automatically check if the provided object is a mock, and if so, register a MockInstance instead of a RealInstance? And likewise for interfaces, automatically performing the Mock.Get(x).As<T>() conversion?

Or would this cause horrible breaking changes? Another idea is a few new methods:

void UseSelfMock<T>(bool enablePrivate  = false, bool? callBase = null) {
	callBase ??= this.CallBase;
	var obj = CreateSelfMock<T>(enablePrivate);
	var mock = Mock.Get(obj);
	Use(mock);
}

void UseSelfMock<T, TInterface>(bool enablePrivate  = false, bool? callBase = null) {
	UseSelfMock<T>(enablePrivate, callBase);
	Combine<T, TInterface>();
}

VerifyAll Should Report All Failures

Right now, VerifyAll throws at the first Mock with failures. Ideally, we throw an AggregateException instead, although that does affect any code that expects MockException from our verification. See #35.

Can't Resolve IEnumerable<Tservice>

Some of our code uses IEnumerable<Tservice> in the constructor to return all registered services. When I use mocker.CreateInstance on such a class, it gets created fine. The corresponding field is not null and seems to be an IEnumerable<Tservice> but when I try to enumerate, it throws a NullReferenceException inside. The same happens regardless if I register Tservice with mocker.Use.

The only workaround I could manage was to hardcode the values like mocker.Use<IEnumerable<IServiceA>>(new[] { mocker.CreateInstance<ServiceA>() }); or mocker.Use<IEnumerable<IServiceA>>(Array.Empty<IServiceA>()) if it's not needed.
Am I doing something wrong?

The exception is this, there is no InnerException.

Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Linq.Enumerable.SelectEnumerableIterator`2.MoveNext()
   at AutomockTester.Program.Main()

It can be reproduced like this:

using Microsoft.Extensions.DependencyInjection;
using Moq.AutoMock;
using System;
using System.Collections.Generic;
using System.Linq;

namespace AutomockTester
{
    public interface IServiceA { int Value { get; } }
    public interface IServiceB { IEnumerable<int> Values { get; } }

    public class ServiceA  : IServiceA { public int Value { get; } = 42; }
    public class ServiceB : IServiceB
    {
        readonly IEnumerable<IServiceA> _services;
        public IEnumerable<int> Values => _services.Select(x => x.Value);
        public ServiceB(IEnumerable<IServiceA> services) { _services = services; }
    }

    class Program
    {
        static void Main()
        {
            var services = new ServiceCollection();
            services.AddSingleton<IServiceA, ServiceA>();
            services.AddSingleton<IServiceB, ServiceB>();
            foreach (var n in services.BuildServiceProvider().GetService<IServiceB>().Values)
                Console.WriteLine("Value: {0}", n);

            var mocker = new AutoMocker();
            // I have to hardcore IEnumerable<IServiceA> in the line below...
            //mocker.Use<IEnumerable<IServiceA>>(new[] { mocker.CreateInstance<ServiceA>() });
            var service = mocker.CreateInstance<ServiceB>();
            // ... otherwise it crashes here at the "in".
            foreach (var n in service.Values)
                Console.WriteLine("Value: {0}", n);
        }
    }
}

Create basic docs folder documenting the various public APIs

Based on discussion from #109

Provide some documentation for each of the following members (grouping by overloads). This documentation should be in markdown files and put inside of a docs directory.

  • Constructors
  • CallBase property
  • Combine
  • CreateInstance
  • CreateSelfMock
  • DefaultValueProperty
  • Get
  • GetMock
  • MockBehavior property
  • Resolvers property; this one in particular probably warrants a longer explanation on the resolver API
  • Setup
  • SetupAllProperties
  • SetupSequence
  • Use
  • Verify
  • VerifyAll (might make sense to merge this with Verify)

Unable to resolve primitive values for mocks

I am running into an issue where I am unable to setup a mock using AutoMocker when the constructor takes in primitive values. For instance, if I want to setup a mock and it takes in a string in the constructor an exception is thrown. I would expect that default would be provided instead of trying to mock it.

That being said, I love the project and use it in all of my repos! Has definitely increased my productivity, with this edge case being the only thing that has caused me any issues. Thanks for all the hard work!

GetMock<T> is not thread-safe

https://github.com/moq/Moq.AutoMocker/blob/master/Moq.AutoMock/AutoMocker.cs

GetMockImplementation is referencing the dictionary TypeMap, which is not a ThreadSafe collection (should be ConcurrentDictionary). This means if you call GetMock in parallel on multiple threads, you can end up with an exception similar to this.

System.InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.
at System.Collections.Generic.Dictionary2.TryInsert(TKey key, TValue value, InsertionBehavior behavior) at System.Collections.Generic.Dictionary2.set_Item(TKey key, TValue value)
at Moq.AutoMock.AutoMocker.GetMockImplementation(Type serviceType, Boolean enablePrivate)
at Moq.AutoMock.AutoMocker.GetMock(Type serviceType, Boolean enablePrivate)
at Moq.AutoMock.AutoMocker.GetMock(Type serviceType)
at Moq.AutoMock.AutoMocker.GetMockTService

Change license

Should we update the license file in the project to the standard MIT license so that it matches moq?

Additional Use overloads

The workflow described in #109 is one that I often use myself. I would like to propose a few additional overloads to make this process easier.

I would propose the following overloads to the Use method:

  • public void Use<TService, TImplementation>() => Use<TService>(CreateInstance<TImplemenation>());
  • public void Use<TImplementation>() => Use<TImplemantion>(CreateInstance<TImplementation>());

Considerations:

  • These overloads are short, but are they clear enough?
  • Should these overloads use a different name; perhaps something more like "CreateAndUse" "Use?

TestGenerator should log warnings when the same class is tested

Reproduction steps:
Put the ConstructorTestsAttribute on top of two test classes and set the same target type for both of the attributes.

Observed:
The output window properly shows an error that the generator produced duplicate files with the same name.

Expected:
There are two things that should be fixed.
First, we should handle two target classes that are in different namespaces but have the same class name. This should be fixed by making the output file names unique.
Second, we should log a warning if the ConstructorTestsAttribute is declared twice for the same target type.

Error when using mocker.Setup but not Mock.Setup

For some reason this:

mocker.Setup<IStreamEncryptor>(
    e => e.Encrypt(It.IsAny<Stream>(), It.IsAny<Stream>(), It.IsAny<RSACryptoServiceProvider>()))
      .Returns(100L);

Compiles, but gives me the following runtime error

System.ArgumentException: Expression is not a method invocation: e => (Object)e.Encrypt(It.IsAny(), It.IsAny(), It.IsAny())

but this works:

var mockStreamEncryptor =new Mock<IStreamEncryptor>();
mockStreamEncryptor.Setup(
    e => e.Encrypt(It.IsAny<Stream>(), It.IsAny<Stream>(), It.IsAny<RSACryptoServiceProvider>()))
      .Returns(100L);
mocker.Use(mockStreamEncryptor);

Any ideas?

Create signed version

Hi,
I like to use AutoMocker, but I need a strong named version,

Regards,
Kjetil.

Is it possible to register Factory Delegates for ViewModel testing

Currently facing an issue where I need to use CreateInstance on a ViewModel that is constructed using a factory delegate from the IoC.

Wiring up the use statements as such will allow the tests to execute, but with the way the type mappings are setup there is not a way to have multiple registrations for types and have them change - i.e. string.

        _mocker.Use<EnumType>(EnumType.Value1);
        _mocker.Use<int>(38);
        _mocker.Use<string>("test1");
        _mocker.Use<string>("test2");
        _mocker.Use<string>("test3");

        _mocker.CreateInstance<ReallyCoolViewModel>();

Any help and/or suggestions would be greatly appreciated!

GetMock<DbSet<MyClass>>() throws TargetInvocationException (EntityFrameworkCore)

Hi,

This code was working on dotnet Core 3.1, AutoMocker 2.0.1:
var mockSet = mocker.GetMock<DbSet<MyClass>>();
DbSet<T> is declared in Microsoft.EntityFrameworkCore.

That line doesn't work in later versions of AutoMocker. They throw the following exception:

  Message: 
    System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
      ----> System.ArgumentNullException : Value cannot be null. (Parameter 'type')
  Stack Trace: 
    RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
    RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
    RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture)
    Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
    ProxyGenerator.CreateClassProxyInstance(Type proxyType, List`1 proxyArguments, Type classToProxy, Object[] constructorArguments)
    ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors)
    CastleProxyFactory.CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, Object[] arguments) line 56
    Mock`1.InitializeInstance() line 322
    Mock`1.OnGetObject() line 340
    Mock.get_Object() line 182
    Mock`1.get_Object() line 294
    GetMyFileProcessorTests.Setup() line 43
    --ArgumentNullException
    IntrospectionExtensions.GetTypeInfo(Type type)
    DbContext.ctor(DbContextOptions options)
    SurrogateContext.ctor(DbContextOptions`1 options) line 11
    SurrogateContextProxy.ctor(IInterceptor[] , DbContextOptions`1 options)

Checking out other issues, I saw the enablePrivate: true argument and gave that a try in v2.3, just in case. But it didn't help.

Is there a workaround?

Thanks!

[Feature request] Implement IServiceProvider

Hi,

I'm in a situation where I inherited some code that uses the service locator pattern, ie.

public class LegacyService
{
    private readonly IServiceProvider _serviceLocator;

    public LegacyService(IServiceProvider sl) => _serviceLocator = sl;

    public void LegacyCodeUnderTest()
    {
         var dep1 = _serviceLocator.GetService(typeof(DataSource));
         var dep2 = _serviceLocator.GetService(typeof(EmailGateway));
         var html = FormatEmail(dep1.Stuff);
         dep2.Send(html);
    }

    private string FormatEmail(object[] data) { ... }
}

I'm refactoring away from this pattern, but in the meantime I'd still like to use AutoMocker to provide mixed fake and real instances of dependencies to the class under test. Is it possible to make the AutoMocker class implement IServiceProvider?

Moq 4.8 Causes Failure on Setup<TService>

Moq 4.8 enforces matching types between setups and methods, which means our base Setup<TService>(Expression<Func<TService, object>> setup) call (using object) fails on a mismatch.

Is there a way to register factory methods?

I'm attempting to use AutoMocker to do some limited scope integration tests. Component tests if you will. Some dependencies I don't care about so they are automatically resolved to mocks. Others I need to be concrete instances. But many of these concrete dependencies have dependencies of their own, which again some are important others are not. I'm currently setting up the test fixtures like so:

            var mocker = new AutoMocker();
            mocker.Use<IDependency1>(mocker.CreateInstance<Dependency1>());
            mocker.Use<IDependency2>(mocker.CreateInstance<Dependency2>());
            mocker.Use<IDependency3>(mocker.CreateInstance<Dependency3>());
            mocker.Use<IDependency4>(mocker.CreateInstance<Dependency4>());

            this.SUT = mocker.CreateInstance<SystemUnderTest>();

The problem I'm having is that CreateInstance is called immediately and if Dependency3 has a dependency on Dependency4 it is getting a mock instead. So the order of Use is highly dependent on which dependencies need to be concrete. Being able to register a factory method like
mocker.Use<IDependency>(x => mocker.CreateInstance<Dependency>());
would allow the creation to be delayed until all the dependencies have been registered.

Of course there could already be a way to do what I'm asking and I'm just not aware of it. If so, can you point me in the right direction?

Documentation

Is there any documentation available for this package?

Create injection of Func<IService>

This is a useful feature. This lines could be avoided if it would be able to inject Func<>

        var sender = CreateStub<IEmailSender>();
        Use<Func<IEmailSender>>(() => sender);
        base.SutInitialize();

What if you have got 3 or more dependencies like this?

These are methods of my base class

    protected T CreateStub<T>()
        where T : class
    {
        return new Mock<T>().Object;
    }
    protected virtual void SutInitialize()
    {
        Sut = CreatePartial<TSut>();
    }

    protected T CreatePartial<T>()
        where T : class
    {
        var instance = Mocker.CreateSelfMock<T>();
        var mock = Mock.Get(instance);
        //I need to add it as it can be I need to do setup against that partial.
        Mocker.Use(mock);
        mock.CallBase = true;
        return instance;
    }

    protected void Use<T>(T service)
        where T : class
    {
        Mocker.Use(service);
    }

Kind regards,
Alex.

[BUG] Cannot find best constructor for..

I have the following code (parts left out for brevity):

 _autoMocker = new AutoMocker(MockBehavior.Strict);

//...

  var logger = new Mock<ISlbLogger>();
  logger.Setup(l => l.Verbose(It.IsAny<string>(), It.IsAny<Object[]>())).Callback<string, object[]>(Log);
  logger.Setup(l => l.Debug(It.IsAny<string>(), It.IsAny<Object[]>())).Callback<string, object[]>(Log);
  logger.Setup(l => l.Info(It.IsAny<string>(), It.IsAny<Object[]>())).Callback<string, object[]>(Log);
  logger.Setup(l => l.Warning(It.IsAny<string>(), It.IsAny<Object[]>())).Callback<string, object[]>(Log);
  _autoMocker.Use(logger);

  var loggerFactory = new Mock<ISlbLoggerFactory>();
  loggerFactory.Setup(f => f.GetLogger(It.IsAny<string>())).Returns(Using<ISlbLogger>());
  _autoMocker.Use(loggerFactory);

When it gets to Using<ISlbLogger>() I get an exception that no constructor can be found. Yet I supplied a mock 2 lines up. Using is simply a shortcut for _autoMocker.CreateInstance<ISlbLogger>()

Exception in question:

Message: 
    System.ArgumentException : Did not find a best constructor for `(...).Logging.ISlbLogger`
    Parameter name: type
  Stack Trace: 
    ConstructorSelector.SelectCtor(Type type, Type[] existingTypes, BindingFlags bindingFlags)
    AutoMocker.CreateArguments(Type type, ObjectGraphContext context)
    AutoMocker.CreateInstance(Type type, Boolean enablePrivate)
    AutoMocker.CreateInstance[T](Boolean enablePrivate)

Am I missing something obvious? Or is this a bug in the logic? I've tried adding the mocked object directly instead of as a mock and I've also tried not using the shortcut, to no avail.

New source generator does not handle generic parameters dependencies

Target class

public class Controller
{
    public Controller(ILogger<Controller> logger) { ... }
}

Test class

[ConstructorTests(typeof(Controller))]
public class ControllerTests
{

}

Observed, the generated test names contain < and > causing the test method name to be invalid.

Expetected: The source generator should never generate invalid method names.

Mocking async methods

In the case of automocking async methods, I would prefer the mocked object to return a Task containing an null, rather than null directly.

Is this supported? If not, is there a work-around not involving doing a setup-method for each mocked method?

Stubbing Values?

Lets say I have a class with 3 dependencies.. A, B and C. If Dependency A has an async method on it that I would like to change the return value of, how is that accomplished with this library?

Using vanilla Moq, you would do something like that following.

var a = new Mock<A>();
a.SetUp(s => s.MyMethod()).ReturnsAsync("some value");

var b = new Mock<B>();
var c = new Mock<C>();

var systemUnderTest = new SystemUnderTest(a.Object, b.Object, c.Object);

With AutoMocker..?

Resolve ILogger from a logger factory

I'm thinking of something like this being added to the built-in resolvers.

private sealed class AutoMockerLoggerResolver : IMockResolver
{
    public void Resolve(MockResolutionContext context)
    {
        if (context.Value is not null) return;

        Type type = context.RequestType;

        if (type == typeof(ILogger))
        {
            ILoggerFactory factory = context.AutoMocker.Get<ILoggerFactory>();
            context.Value = factory.CreateLogger(string.Empty);
        }
        else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>))
        {
            ILoggerFactory factory = context.AutoMocker.Get<ILoggerFactory>();

            context.Value = typeof(AutoMockerLoggerResolver)
                .GetMethod(nameof(CreateLogger), BindingFlags.Static | BindingFlags.NonPublic)
                .MakeGenericMethod(type.GenericTypeArguments[0])
                .Invoke(null, new object[] { factory });
        }
    }

    private static ILogger<T> CreateLogger<T>(ILoggerFactory factory)
        => factory.CreateLogger<T>();
}

SetupSequence shortcut

I created a method on the AutoMocker for SetupSequence. I think its a "nice to have" shortcut, when adding a sequence of results.

Are you interested in a PR for it?

Setting default behavior on Mocks

This appears to be an updated version of Moq.Contrib, correct?

In any case, I want to set the behavior of the mock to MockBehavior.Strict by default. Is there any way to do this? It appears the default behavior is loose.

Allow for recursively creating mock parameters

This is to track the feature request that was initially attempted in PR #23

Because all constructor parameters are required when creating a mock, if one of the parameters is a class use auto mocker to create the instance, and recursively populate constructor parameters.

Outstanding questions:

  • What should the API look like for enabling this behavior? It is enabled by default?
  • What do we do on circular dependencies?

Cannot create analyzer during build.

I migrated over to using Moq.AutoMocker from a homebrew version using Unity.
Building locally in debug and release works.

Using our docker based release build comes up with the following error. This may just require a binding redirect, I didn't dig into it too much because the docker based build takes forever and is a bit hard to debug.

CSC : error CS8032: An instance of analyzer Moq.AutoMocker.TestGenerator.UnitTestSourceGenerator cannot be created from
C:\Users\ContainerAdministrator\.nuget\packages\moq.automock\3.4.0\analyzers\dotnet\cs\Moq.AutoMocker.TestGenerator.dll : 
Could not load file or assembly 'Microsoft.CodeAnalysis, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
or one of its dependencies. The system cannot find the file specified.

I'm not using the TestGenerator, and tried to exclude it from the build using the following

<PackageReference Include="Moq.AutoMock" Version="3.4.0">
    <ExcludeAssets>analyzers</ExcludeAssets>
</PackageReference>

It sounds like this doesn't actually work though - dotnet/sdk#1212

I was able to downgrade to 3.3.0 to get past the issue, but maybe it makes sense to split the SourceGenerator into a separate nuget package.

"Did not find a best constructor concrete type" error after updating to 2.1

This started happening with 2.1, the same code is fine with 2.0.1.

If a class has a constructor parameter of type Microsoft.AspNetCore.Http.HttpRequest or Microsoft.AspNetCore.Routing.LinkGenerator (note that both are concrete types) then exceptions of the following kind are thrown:

System.ArgumentException : Did not find a best constructor for `Microsoft.AspNetCore.Http.HttpRequest` (Parameter 'type')
at Moq.AutoMock.ConstructorSelector.SelectCtor(Type type, Type[] existingTypes, BindingFlags bindingFlags)
at Moq.AutoMock.AutoMocker.CreateArguments(Type type, ObjectGraphContext context)
at Moq.AutoMock.Resolvers.MockResolver.Resolve(MockResolutionContext context)
at Moq.AutoMock.AutoMocker.Resolve(Type serviceType, Object initialValue, ObjectGraphContext resolutionContext)
at Moq.AutoMock.AutoMocker.Resolve(Type serviceType, ObjectGraphContext resolutionContext)
at Moq.AutoMock.AutoMocker.GetMockImplementation(Type serviceType)
at Moq.AutoMock.AutoMocker.GetMock[TService]()
at MyProject.Tests.UnitTests.Services.MyClassTests.<>c__DisplayClass10_0.<CreateClaimsPrincipal>b__0(AutoMocker mocker) in C:\Agent3\work\FINI\src\Modules\MyProject\Tests\MyProject.Tests\UnitTests\Services\MyClassTests.cs:line 170
at Lombiq.Tests.Helpers.MockHelper.CreateAutoMockerInstance[T](Action`1 configurator, AutoMocker& mocker) in C:\Agent3\work\FINI\test\Lombiq.Tests\Helpers\MockHelper.cs:line 42
at MyProject.Tests.UnitTests.Services.MyClassTests.CreateClaimsPrincipal(User user, UserVerificationSettings settings, IDictionary`2 cookies, UserProfilePart userProfilePart) in C:\Agent3\work\FINI\src\Modules\MyProject\Tests\MyProject.Tests\UnitTests\Services\MyClassTests.cs:line 137
at MyProject.Tests.UnitTests.Services.MyClassTests.DaysSinceLastVerificationClaimShouldBeAccurate() in C:\Agent3\work\FINI\src\Modules\MyProject\Tests\MyProject.Tests\UnitTests\Services\MyClassTests.cs:line 102

I'd guess this has to do something with #86.

Behaviour of Get

The behaviour of the Get method only returns a concrete object if it has already been registered whereas GetMock will either return the mock object already registered or will create a new mock and register it.

Is there any reason why calling Get for a type that has not been registered cannot do the same thing? That is, create a new mock and return the mocked object. This would be equivalent to calling mocker.GetMock<T>().Object.

Implement `System.IServiceProvider` in `AutoMocker`

AutoMocker already essentially is a service provider. It would be nice if it implemented System.IServiceProvider so it can be used as a substitute for one when testing infrastructure code that relies on ActivatorUtilities.CreateInstance.

CreateInstance<T> throws NullReference if parameter is a Func

Hi.

I'm trying to clean up some unit tests by using AutoMocker. One of the types being tested, however, has Func in it's constructor (these are Caliburn.Mico view models). These Func<> parameters result in AutoMocker.CreateInstance<> throwing a null reference exception like so :

System.NullReferenceException occurred
_HResult=-2147467261
_message=Object reference not set to an instance of an object.
HResult=-2147467261
IsTransient=false
Message=Object reference not set to an instance of an object.
Source=Moq.AutoMock
StackTrace:
at Moq.AutoMock.AutoMocker.CreateArgumentsT in C:\Users\tkellogg\projects\Moq.AutoMocker\Moq.AutoMock\AutoMocker.cs:line 35
InnerException:

CreateSelfMock uses different instance of mocked service than resolving from AutoMocker

This is a breaking change from 3.0, I updated the nuget package in my solution from 3.0 to 3.1 and suddenly tests failed.
Consider the following example, this was fine in 3.0 but fails in 3.1:

[Fact]
public void CreateSelfMockTest()
{
    var mocker = new AutoMocker();
    var service = mocker.CreateSelfMock<AbstractService>();
    service.Dependency.Should().BeSameAs(mocker.GetMock<IDependency>().Object);
}

public abstract class AbstractService
{
    public IDependency Dependency { get; }
    public AbstractService(IDependency dependency) => Dependency = dependency;
}

public interface IDependency { }

This fails (in 3.1) with the following message:

Expected service.Dependency to refer to MockIDependency:2.Object
, but found MockIDependency:1.Object

Feature: Implement IDisposable

There are times that AutoMocker may provide (or be given) an object which implements IDisposable. It would be good if these could be disposed along with the mocker. However, any project with analyzers will get build warnings/errors in their tests because of no longer disposing of the object. So either,

  1. A breaking change
  2. Some form of an opt-in? using var mocker = new AutoMocker().AsDisposable();

AutoMocker does not expose non-generic overloads

I am opening this issue to see if this is something that is desirable (I am happy to submit PRs if it is).

On several of my projects that use various DI containers, I tend to write a class that bridges between the DI container and AutoMocker to have the DI container automatically fill requests with mocks from AutoMocker.
The issue is that the DI containers will pass the service type as a System.Type rather than calling a generic method. I tend to write extension methods on AutoMocker to expose non-generic overloads for the methods Get, GetMock, and CreateInstance.

Things like this:

public static object Get(this AutoMocker mocker, Type serviceType)
{
    return typeof(AutoMocker).GetMethod(nameof(AutoMocker.Get))
            .MakeGenericMethod(serviceType)
            .Invoke(mocker, new object[0]);
}

Is this something that would be considered?

Expose a way to iterate over all resolved objects (i.e. expose `typeMap`)

I have a set of integration tests that span over a wide set of services. These services utilize the Microsoft.Extensions.Logging infrastructure for logging, and as such, each different service injects its own variant of a logger in the form of an ILogger<TService>.

If I want to write assertions/verifications that no errors were logged by any of the services in the integration tests, I have to manually write the following for every possible logger variant (and hope I don't miss any):

Mocker.Verify<ILogger<ServiceOne>>(l => l.Log(
    LogLevel.Error, 
    It.IsAny<EventId>(), 
    It.Is<It.IsAnyType>((o, _) =>true), 
    It.IsAny<Exception>(),
    It.Is<Func<It.IsAnyType, Exception, string>>((v, t) => true)),
    Times.Never()
);
Mocker.Verify<ILogger<ServiceTwo>>(l => l.Log(
    // ...
);
// and so on

I'd like to be able to iterate over all the objects that AutoMocker has created for me, use reflection to determine if the type of each is an ILogger, and then manually inspect the .Invocations of the mock to perform the verification. I see that this is all stored in typeMap, but doesn't seem to be exposed in any way.

TypeLoadException when using CreateInstance with Enum in Constructor.

I'm using CreateInstance to call a Validator class and this validator has some variables in constructor, one of then is an enum.
When i'm using this enum i'm gotting a TypeLoadException.

System.ArgumentException : GenericArguments[0], 'CrossCutting.NotaFiscal.Enums.EnumFinalidadeNota', on 'Moq.Mock1[T]' violates the constraint of type 'T'. ---- System.TypeLoadException : GenericArguments[0], 'CrossCutting.NotaFiscal.Enums.EnumFinalidadeNota', on 'Moq.IMock1[T]' violates the constraint of type parameter 'T'.

I'm creating a Fixture to control the mocker.

[CollectionDefinition(nameof(NotaFiscalUnitTestCollection))]
public class NotaFiscalUnitTestCollection : ICollectionFixture<NotaFiscalUnitTestFixture> { }
public class NotaFiscalUnitTestFixture : IDisposable
{
	public readonly AutoMocker Mocker;
	private NotaFiscalMaterialValidator _notaFiscalMaterialValidator;

	public NotaFiscalUnitTestFixture()
	{
		Mocker = new AutoMocker();
	}

	public NotaFiscalMaterialValidator GetNotaFiscalMaterialValidator()
	{
		if (_notaFiscalMaterialValidator == null)
			_notaFiscalMaterialValidator = Mocker.CreateInstance<NotaFiscalMaterialValidator>();
		return _notaFiscalMaterialValidator;
	}

	public void Dispose()
	{
	}
}

My enum:

public enum EnumFinalidadeNota
{
	[Description("NF-e Normal")]
	Normal = 1,

	[Description("NF-e Complementar")]
	Complementar = 2,

	[Description("NF-e de Ajuste")]
	Ajuste = 3,

	[Description("Devolucao de mercadoria")]
	DevolucaoMercadoria = 4
}

And my NotaFiscalMaterial Validator

public class NotaFiscalMaterialValidator : ValidatorEntityBase<Domain.Entities.NotaFiscalMaterial>
{
	private readonly EnumFinalidadeNota _finalidadeNota;
	private readonly bool? _operacaoMovimentaEstoque;
	public NotaFiscalMaterialValidator(IServiceGlobalization globalization, EnumFinalidadeNota finalidadeNota, bool? operacaoMovimentaEstoque) : base(globalization)
	{
		_finalidadeNota = finalidadeNota;
		_operacaoMovimentaEstoque = operacaoMovimentaEstoque;
	}        
}

I'm using Moq.AutoMocker in

version 2.3.0.0

Any idea what might be causing this exception?

AutoMocker.Combine wipes out any setups already made against the target interfaces.

For the following code, I'd expect that the order in which I call Combine relative to my Setups not matter, but it ends up that Combine must come before the Setups because it wipes out all existing setups made against the target interface.

Fiddle: https://dotnetfiddle.net/NWR0vx

using System;
using System.Collections.Generic;
using Moq;
using Moq.AutoMock;
using Xunit;

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("DynamicProxyGenAssembly2")]
					
public class Program
{
	public static void Main()
	{
		var mocker1 = new AutoMocker(MockBehavior.Loose);
		mocker1.Combine<IDerivedInterface, IBaseInterface>();
		mocker1.GetMock<IDerivedInterface>().Setup(x => x.Foo()).Returns(() => "42");
		
		var mocker2 = new AutoMocker(MockBehavior.Loose);
		mocker2.GetMock<IDerivedInterface>().Setup(x => x.Foo()).Returns(() => "42");
		mocker2.Combine<IDerivedInterface, IBaseInterface>();
		
		Console.WriteLine("mocker1 - base");
		Assert.Equal("42", mocker1.Get<IBaseInterface>().Foo());
		Console.WriteLine("mocker1 - derived");
		Assert.Equal("42", mocker1.Get<IDerivedInterface>().Foo());
		
		Console.WriteLine("mocker2 - base");
		Assert.Equal("42", mocker2.Get<IBaseInterface>().Foo());
		Console.WriteLine("mocker2 - derived");
		Assert.Equal("42", mocker2.Get<IDerivedInterface>().Foo());
	}
}

interface IBaseInterface {
	string Foo();
}
interface IDerivedInterface : IBaseInterface {
	string Bar();
}

Expected output:
No assertion failures.

Actual output:

mocker1 - base
mocker1 - derived
mocker2 - base
Unhandled exception. Xunit.Sdk.EqualException: Assert.Equal() Failure
Expected: 42
Actual:   (null)
   ...
   at Program.Main()
Command terminated by signal 6

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.