Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for custom default value generators (i.e. make default value providers part of the public API) #533

Merged
merged 16 commits into from
Nov 25, 2017

Conversation

stakx
Copy link
Contributor

@stakx stakx commented Nov 25, 2017

This is a follow-up to #366, where I said:

I'm closing this briefly. I suspect the API could be simplified a little more.

Almost half a year later, I'm back with this PR. It allows implementation of custom default value providers:

sealed class CustomDefaultValueProvider : DefaultValueProvider
{
    protected override object GetDefaultValue(Type type, Mock mock)
    {
        return; // any instance of the requested `type`
    }

    // optionally override `GetDefaultParameterValue` and/or `GetDefaultReturnValue`
    // if you need to know about the context (i. e. what Moq needs a default value for).
}

Which is massively simpler than what the earlier PR proposed. A mock—or mock repository—can then be set up to use that provider as follows:

mock.DefaultValueProvider = new CustomDefaultValueProvider();

(For backwards compatibility and ease of use, Mock.DefaultValue can still be set to DefaultValue.Empty or DefaultValue.Mock.)

This is meant to be both an extension point for better interoperation with libraries such as AutoFixture, and as a potential prerequisite for resolving #173 and #330 (which ask for functional changes regarding DefaultValue.Empty, which possibly means its behavior should be configurable in order to not introduce breaking changes).

This refactoring will pay off later because it allows us to extract
`DefineDefault` from `IDefaultValueProvider` and move it into `Mock`.
This in turn will make it possible to turn default value providers
into singletons.
by removing `IDefaultValueProvider.DefineDefault` and implementing
the same functionality directly in the `Mock.GetDefaultValue` method
added earlier.
This commit also includes a small breaking change: `Mock.DefaultValue`
is no longer virtual, as there is now only one possible correct way of
implementing it: deriving its value from `Mock.DefaultValueProvider`
and updating that same other property in the setter.
First, if the default value provider mechanism is to be more generic
in nature, it should be possible for custom providers to create "inner
mocks" without having access to `Mock` internals. This commit makes
it possible for any default value provider to participate in This
mechanism simply by returning a mocked object.

Second, this refactoring is prerequisite to changing the `Provide-
Default` method's signature (so it accepts a `Type` instead of a
`MethodInfo`).
This commit replaces the `IDefaultValueProvider` interface with a new
abstract base class `DefaultValueProvider`, which is meant to eventu-
ally become part of the public API.
Originally, those methods without the suffix were supposed to be the
ones performing parameter validation. However, Moq doesn't actually
call those.

So instead let's remove the validating methods and give the "clean"
method names to the protected methods that are overridden in derived
classes.

Also, remove unit tests associated with the validation that no longer
happens. Add `Debug.Assert`s to document the new (implicit) contract.
@stakx stakx added this to the v4.8.0 milestone Nov 25, 2017
 * Move `Mock.configuredDefaultValues` field to `Mock<T>`
 * Fix whitespace
@stakx stakx merged commit 7180644 into devlooped:develop Nov 25, 2017
@stakx stakx deleted the defaultvalueprovider branch November 25, 2017 12:54
@devlooped devlooped locked and limited conversation to collaborators Sep 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant