سؤال

I have done something like the following

public class Foo
{
    public Bar { get; set; }
}

public class Bar
{
    internal Bar(string id)
    {}
}

public static class Bars
{
     public static class TypeOne
     {
           public static readonly SimpleBar = new Bar("id-for-type1-simple-bar");
     }
}

now, I added an InternalsVisibleTo to my in my unit-test-assembly to be able to access the internal Bar ctor and then I did:

var fixture = new Fixture();
fixture.Register(() => new Bar(fixture.CreateAnonymous<string>()));
var foo = fixture.CreateAnonymous<Foo>();

Question:
Was that the "right" way to utilize AutoFixture or is there a better one?

هل كانت مفيدة؟

المحلول

Couldn't you just do something like this instead?

fixture.Inject(Bars.TypeOne.SimpleBar);

This is all public. No need for InternalsVisibleTo, I think...

نصائح أخرى

This code works since you already have a public static class that references Bar, this works without setting the InternalsVisibleTo attribute

        var fixture = new Fixture().Customize(new AutoMoqCustomization());

        fixture.Inject(Bars.TypeOne.SimpleBar);

        var sut = fixture.CreateAnonymous<Foo>();

        sut.Should().NotBeNull();
        sut.Bar.Should().NotBeNull();
        sut.Bar.Should().Be(Bars.TypeOne.SimpleBar);

Never ever go down the road of InternalsVisibleTo - Don't make me start the list, but it starts with every part of your system including all test helpers being strong named.

If you definitely can't (think long and hard about it - most of the time you're far better off putting internals you dont consider part of your public api into a namespace so they don't clutter anything - e.g. Xunit.Sdk and various .Internal sub-namespaces I've used for my employer), then the correct way to manage this exposing of stuff For Tests Only is the notion of For Tests Only. NB the reason this has a name is that it is (correctly) called out as an antipattern in the xUnit Test Patterns book.


Now, to answer your question...

  1. CONSIDER hiding stuff that users shouldnt generally require in a separate namespace
  2. NEVER use InternalsVisibleTo
  3. DONT use Test Only Code

Expose a factory which is only exposed in Internal (maybe DEBUG?) Builds of your software (but ideally you'd have it unconditional in another namespace):

#if INCLUDE_FOR_TEST_ONLY
public static class BarsForTestOnly
{
    public static Bar Create( string id )
    {
        return new Bar( id );
    }
}
#endif

And use it like this:

#if INCLUDE_FOR_TEST_ONLY
public class Facts
{

[Fact]
public void Fact()
{
    Fixture fixture = new Fixture();
    fixture.Register( ( string name ) => BarsForTestOnly.Create( name ) );
    var anonymousBar = fixture.CreateAnonymous<Bar>();
}

[Fact]
public void FactSyntax2() // Just a variant of Fact above
{
    Fixture fixture = new Fixture();
    fixture.Register<string, Bar>( BarsForTestOnly.Create );
    var anonymousBar = fixture.CreateAnonymous<Bar>();
}

[Fact]
public void UsingFromFactory()
{
    Fixture fixture = new Fixture();
    fixture.Customize<Bar>(  x=> x.FromFactory<string>( BarsForTestOnly.Create ) );
    var anonymousBar = fixture.CreateAnonymous<Bar>();
}
#endif

Alternately, to make what you have Just Work, you can do:

[Fact]
public void UsingCtor()
{
    Fixture fixture = new Fixture();
    fixture.Register( ( string name )=> new Bar( name ) );
    var anonymousBar = fixture.CreateAnonymous<Bar>();
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top