Search code examples
c#unit-testingautofixtureautomocking

AutoFixture.AutoMoq supply a known value for one constructor parameter


I've just started to use AutoFixture.AutoMoq in my unit tests and I'm finding it very helpful for creating objects where I don't care about the specific value. After all, anonymous object creation is what it is all about.

What I'm struggling with is when I care about one or more of the constructor parameters. Take ExampleComponent below:

public class ExampleComponent
{
    public ExampleComponent(IService service, string someValue)
    {
    }
}

I want to write a test where I supply a specific value for someValue but leave IService to be created automatically by AutoFixture.AutoMoq.

I know how to use Freeze on my IFixture to keep hold of a known value that will be injected into a component but I can't quite see how to supply a known value of my own.

Here is what I would ideally like to do:

[TestMethod]
public void Create_ExampleComponent_With_Known_SomeValue()
{
    // create a fixture that supports automocking
    IFixture fixture = new Fixture().Customize(new AutoMoqCustomization());

    // supply a known value for someValue (this method doesn't exist)
    string knownValue = fixture.Freeze<string>("My known value");

    // create an ExampleComponent with my known value injected 
    // but without bothering about the IService parameter
    ExampleComponent component = this.fixture.Create<ExampleComponent>();

    // exercise component knowning it has my known value injected
    ...
}

I know I could do this by calling the constructor directly but this would no longer be anonymous object creation. Is there a way to use AutoFixture.AutoMock like this or do I need to incorporate a DI container into my tests to be able to do what I want?


EDIT:

I probably should have been less absract in my original question so here is my specific scenario.

I have an ICache interface which has generic TryRead<T> and Write<T> methods:

public interface ICache
{
    bool TryRead<T>(string key, out T value);

    void Write<T>(string key, T value);

    // other methods not shown...  
}

I'm implementing a CookieCache where ITypeConverter handles converting objects to and from strings and lifespan is used to set the expiry date of a cookie.

public class CookieCache : ICache
{
    public CookieCache(ITypeConverter converter, TimeSpan lifespan)
    {
        // usual storing of parameters
    }

    public bool TryRead<T>(string key, out T result)
    {
        // read the cookie value as string and convert it to the target type
    }

    public void Write<T>(string key, T value)
    {
        // write the value to a cookie, converted to a string

        // set the expiry date of the cookie using the lifespan
    }

    // other methods not shown...
}

So when writing a test for the expiry date of a cookie, I care about the lifespan but not so much about the converter.


Solution

  • You have to replace:

    string knownValue = fixture.Freeze<string>("My known value");
    

    with:

    fixture.Inject("My known value");
    

    You can read more about Inject here.


    Actually the Freeze extension method does:

    var value = fixture.Create<T>();
    fixture.Inject(value);
    return value;
    

    Which means that the overload you used in the test actually called Create<T> with a seed: My known value resulting in "My known value4d41f94f-1fc9-4115-9f29-e50bc2b4ba5e".