Skip to content

CreateSelfMock has some sharp edges #134

@ascott18

Description

@ascott18

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>();
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions