-
Notifications
You must be signed in to change notification settings - Fork 337
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
AutoMoq a concrete dependency #1202
Comments
Just freeze Check this page of the booklet I wrote for my developers: https://docs.educationsmediagroup.com/unit-testing-csharp/autofixture/combining-autofixture-with-nunit-and-moq |
Unfortunately that doesn't work as For completeness the attribute is: public AutoMoqDataAttribute()
: base(() => new Fixture().Customize(new AutoMoqCustomization()))
{ } Note that for interfaces and abstract class it doesn't appear to matter if you freeze the mock wrapper or the interface and then either get the mock or use I believe it is entirely correct that a concrete class in the parameters should give you a real copy, otherwise your |
Then I don't understand your issue. Why do you need to use Moq at all? |
|
Current workaround: [Theory, AutoMoqData]
public async Task Can_register_a_single_service_successfully(
[Frozen] ILogger<ServiceDiscoveryUsingIdentityServer> logger,
[Frozen] IAuditor<ServiceDiscoveryUsingIdentityServer> auditor,
[Frozen] Mock<IdentityServerOptions> identityServerOptions,
... the other dependencies.
)
{
//Arrange
var sut= new ServiceDiscoveryUsingIdentityServer(logger, auditor, identityServerOptions, identityService, authorizationService, grpcService);
} This makes it a little messy to have to list all the dependencies in every test when I'm only usually needing the identityServerOptions mock for most of the test cases. |
@Euan-McVie sorry for a late reply. While I was not around when AutoMoq was developed, I believe this behavior was intended. As you probably know AutoMoq can inject mocks two ways either as a mock and as the mocked type. If we were to move the auto-mocking customizations closer to the beginning of the pipeline, then most types would be resolved as mocks. This is not desirable because then the types dependencies would be Now it might seem logical that the As a workaround for your issue I suggest customizing the concrete type to be created from a mock. public class CustomCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<IdentityServerOptions>(
x => x.FromFactory<IFixture>(
f => f.Create<Mock<IdentityServerOptions>>().Object));
}
} Since you would have already frozen the mock in your test parameter when you'd requested it in your SUT you would receive the same instance. [Theory, AutoMoqData]
public async Task Can_register_a_single_service_successfully(
[Frozen] Mock<IdentityServerOptions> identityServerOptions,
ServiceDiscoveryUsingIdentityServer sut) I will leave this issue open for a little while, in case you have more questions on this topic. |
Thanks for the response. Would it work if I created a custom [Theory, AutoMoqData]
public async Task Can_register_a_single_service_successfully(
[Frozen, Mock(typeof(IdentityServerOptions))] IdentityServerOptions identityServerOptions,
[Frozen] ILogger<ServiceDiscoveryUsingIdentityServer> logger,
[Frozen] IAuditor<ServiceDiscoveryUsingIdentityServer> auditor,
ServiceDiscoveryUsingIdentityServer sut) This would be preferred as then the standard Would this possibly work (not had a chance to test yet myself), or would it not combine properly with the public AutoMoqDataAttribute()
: base(() => new Fixture().Customize(new AutoMoqCustomization()))
{ } Thanks |
@Euan-McVie I suppose you could indeed do that. Here's a naive implementation of a customization that could achieve parameter specific mocking public class MockCustomization : ICustomization
{
public MockCustomization(ParameterInfo parameterInfo)
{
ParameterInfo = parameterInfo;
}
public ParameterInfo ParameterInfo { get; }
public void Customize(IFixture fixture)
{
var mockedType = ParameterInfo.ParameterType.GetGenericArguments()[0];
fixture.Customizations.Add(new MockRelay(new ExactTypeSpecification(mockedType)));
}
} You could then define an attribute that uses it [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public class MockAttribute : Attribute, IParameterCustomizationSource
{
public ICustomization GetCustomization(ParameterInfo parameter)
{
return new MockCustomization(parameter);
}
} and finally the test would look something like this [Theory]
[AutoData]
public void DependencyShouldBeSameAsMockedObject(
[Frozen][Mock] Mock<DependencyClass> dependencyMock,
SystemUnderTest sut)
{
Assert.Same(dependencyMock.Object, sut.Dependency);
} |
Closing the issue. |
Looks great thanks. |
@aivascu do you think the types above could be incorporated in the AutoMoq library? They seem generic and general purpose enough to deserve the honour. |
@Kralizek yes it might be useful to have it in the AutoMoq lib. |
Finally had a chance to test it and it works great. public void Customize(IFixture fixture)
{
Type? mockedType = (typeof(IMock<object>).IsAssignableFrom(ParameterInfo.ParameterType))
? ParameterInfo.ParameterType.GetGenericArguments()[0]
: ParameterInfo.ParameterType;
fixture.Customizations.Add(new MockRelay(new ExactTypeSpecification(mockedType)));
} Allows [Theory]
[AutoData]
public void DependencyShouldBeSameAsMockedObject(
[Frozen][Mock] DependencyClass dependencyMock,
SystemUnderTest sut)
{
Assert.Same(dependencyMock, sut.Dependency);
} |
Hi,
I am trying to use a Moq of a concrete dependency.
This throws an error where AutoFixture is trying to create a real instance of
IdentityServerOptions
to inject into mysut
instead of using the frozen mock.If I remove the sut and manually create passing in the
identityServerOptions.Object
then it all works, so my working theory is that autofixture/automoq is not picking up that the frozen moq can satisfy the dependency and so tries to create a new instance.I also tried
Frozen(Matching.DirectBaseType)
as the proxy generated by moq inherits from the requested value, but still no luck.Is there any way around this as I can't change
IdentityServerOptions
as it's 3rd party and have more variables to inject to my sut, which makes the workaround a bit messy when I only need to access the one from my example.Thanks
Euan
The text was updated successfully, but these errors were encountered: