AutoFixture and private properties
Asked Answered
P

1

15

Can I instruct AutoFixture to fill also private properties, annotated with a specific attribute such as Ninject.Inject, of all classes? The source seems to scan for public properties only: 1. This question provides a solution for specific MyClass with private setter, but not for private property or all classes: 2.

I'm using Moq to mock the services and in the end I'd like to fill the properties with those mocks. The following setup works fine if I expose the MyService dependency as public.

Some example code:

public class MyController {
    [Inject]
    private IMyService MyService { get; set; }

    public void AMethodUsingMyService() {
        MyService.DoSomething();
        // ...
    }

    // ...
}

public class MyService : IMyService {
    public void DoSomething()
    {
        // ...
    }

    // ...
}

public class MyControllerTest {
    [Theory]
    [AutoMoqData]
    public void MyTest(MyController controller) {
        controller.AMethodUsingMyService();
    }
}
Penneypenni answered 28/3, 2014 at 8:12 Comment(3)
NB Ninject 2 or later doesn't support injecting privates (and it shouldnt as covered in 'Mark's answer). Really really don't do thatPhonic
I'm using version 3.0.1.10 and injecting privates works fine as long as you instruct Ninject to inject them (InjectNonPublic). I agree with Mark's answer!Penneypenni
Damn had thought that this option also died in the V2 reimpl but I stand corrected. That means the docs are wrong (it says injecting privates was cut from V2 in lots of places when I last looked and made things consistent 2 years back). Sadly I won't be able to motivate myself to fix those cases in the wiki - hope someone else can.Phonic
G
14

AutoFixture doesn't have built-in support for assigning values to non-public fields or properties. This is by design.

AutoFixture is a utility library for unit testing, and unit tests shouldn't directly invoke private members of the SUT.

AutoFixture was originally build as a tool for Test-Driven Development (TDD), and TDD is all about feedback. In the spirit of GOOS, you should listen to your tests. If the tests are hard to write, you should consider your API design. AutoFixture tends to amplify that sort of feedback, so my first reaction is to challenge the motivation for wanting to do this.

Since you're referencing NInject, it looks as though you're using Dependency Injection (DI). However, DI with private Property Injection sounds exotic. Consider making the properties public, or even better, use Constructor Injection instead of Property Injection.

This will enable AutoFixture to automatically work like an Auto-Mocking Container.

However, AutoFixture is a very extensible library, so if you really must do this, it should be possible to write an extension that can write to private properties, but it's not going to be the simplest AutoFixture extension ever written.

George answered 28/3, 2014 at 9:5 Comment(3)
Thanks for the inspiring comments! I'm indeed using DI and AutoFixture with Moq as an auto-mocking container. I'm using property injection for my classes, because constructor injection seems like boilerplate to me. I'm also using private properties to prevent modifications from outside to prevent any possible bugs. Works fine as long as the (DI+test) tools are able to set the private fields :) I guess, I should learn to live with the boilerplate and prefer constructor injection to do stuff properly as that's the place where dependencies should be managed anyway. Many thanks for AutoFixture!Penneypenni
I'm not sure I understand why constructors are more boilerplate than properties... In any case, if you have dependencies, you should prefer Constructor Injection. For more details, read my book :)George
It's much easier to annotate a field than to receive it in the constructor and then assign it to a field. Granted, it's way too easy to add too many dependencies with field injection, but the IDE warns you about that. Also, to be honest, I've grown up with field injection, and it seems to be a bad habit of mine. Lesson learned, prefer constructor injection. Thanks for educating me! Oh, I should definitely read some .NET books, as this is my first .NET project!Penneypenni

© 2022 - 2024 — McMap. All rights reserved.