Frage

Ich bin während meiner Arbeit auf eine Klasse gestoßen, die so aussieht:

public class MyObject
{
  public int? A {get; set;}
  public int? B {get; set;}
  public int? C {get; set;}
  public virtual int? GetSomeValue()
  {
    //simplified behavior:
    return A ?? B ?? C;
  }  
}

Das Problem ist, dass ich einen Code habe, der auf A, B und C zugreift und die Methode "GetomeValue () nennt (jetzt würde ich sagen, dass dies kein gutes Design ist, aber manchmal sind meine Hände gebunden ;-)). Ich möchte ein Schein dieses Objekts erstellen, das gleichzeitig a, b und c auf einige Werte eingestellt ist. Also, wenn ich MOQ als solches verwende:

var m = new Mock<MyObject>() { DefaultValue = DefaultValue.Mock };

Lassen Sie mich ein Ergebnis bei der GetomeValue () -Methode einrichten, aber alle Eigenschaften werden auf null eingestellt (und alle mithilfe von Setup () einrichten, ist ziemlich umständlich, da das reale Objekt ein böses Datenobjekt ist und mehr Eigenschaften hat als in oben oben vereinfachtes Beispiel).

Andererseits verwenden Sie eine autofixe mit wie folgt:

var fixture = new Fixture();
var anyMyObject = fixture.CreateAnonymous<MyObject>();

Verlässt mich ohne die Fähigkeit, einen Anruf bei GetomeValue () -Methode zu betrügen.

Gibt es eine Möglichkeit, die beiden zu kombinieren, anonyme Werte und die Möglichkeit, Anrufergebnisse einzurichten?

Bearbeiten

Basierend auf der Antwort von Nemesv habe ich die folgende Dienstprogrammmethode abgeleitet (hoffe, ich habe es richtig verstanden):

public static Mock<T> AnonymousMock<T>() where T : class
{
  var mock = new Mock<T>();
  fixture.Customize<T>(c => c.FromFactory(() => mock.Object));
  fixture.CreateAnonymous<T>();
  fixture.Customizations.RemoveAt(0);
  return mock;
}
War es hilfreich?

Lösung

Dies ist Eigentlich möglich mit Autofixure zu tun, aber es erfordert ein bisschen Optimierung. Die Erweiterbarkeitspunkte sind alle da, aber ich gebe zu, dass in diesem Fall die Lösung nicht besonders auffindbar ist.

Es wird noch schwieriger, wenn Sie möchten, dass es mit verschachtelten/komplexen Typen funktioniert.

Angesichts der MyObject Klasse oben und dies MyParent Klasse:

public class MyParent
{
    public MyObject Object { get; set; }

    public string Text { get; set; }
}

Diese Unit -Tests bestehen alle:

public class Scenario
{
    [Fact]
    public void CreateMyObject()
    {
        var fixture = new Fixture().Customize(new MockHybridCustomization());

        var actual = fixture.CreateAnonymous<MyObject>();

        Assert.NotNull(actual.A);
        Assert.NotNull(actual.B);
        Assert.NotNull(actual.C);
    }

    [Fact]
    public void MyObjectIsMock()
    {
        var fixture = new Fixture().Customize(new MockHybridCustomization());

        var actual = fixture.CreateAnonymous<MyObject>();

        Assert.NotNull(Mock.Get(actual));
    }

    [Fact]
    public void CreateMyParent()
    {
        var fixture = new Fixture().Customize(new MockHybridCustomization());

        var actual = fixture.CreateAnonymous<MyParent>();

        Assert.NotNull(actual.Object);
        Assert.NotNull(actual.Text);
        Assert.NotNull(Mock.Get(actual.Object));
    }

    [Fact]
    public void MyParentIsMock()
    {
        var fixture = new Fixture().Customize(new MockHybridCustomization());

        var actual = fixture.CreateAnonymous<MyParent>();

        Assert.NotNull(Mock.Get(actual));
    }
}

Was ist in Mockhybridcustomisierung? Dies:

public class MockHybridCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customizations.Add(
            new MockPostprocessor(
                new MethodInvoker(
                    new MockConstructorQuery())));
        fixture.Customizations.Add(
            new Postprocessor(
                new MockRelay(t =>
                    t == typeof(MyObject) || t == typeof(MyParent)),
                new AutoExceptMoqPropertiesCommand().Execute,
                new AnyTypeSpecification()));
    }
}

Das MockPostprocessor, MockConstructorQuery und MockRelay Klassen sind in der definiert Automoq -Erweiterung Zum Autofixieren müssen Sie diese Bibliothek ein Hinweis auf diese Bibliothek hinzufügen. Beachten Sie jedoch, dass es nicht erforderlich ist, das hinzuzufügen AutoMoqCustomization.

Das AutoExceptMoqPropertiesCommand Die Klasse ist auch für diesen Anlass individuell gebaut:

public class AutoExceptMoqPropertiesCommand : AutoPropertiesCommand<object>
{
    public AutoExceptMoqPropertiesCommand()
        : base(new NoInterceptorsSpecification())
    {
    }

    protected override Type GetSpecimenType(object specimen)
    {
        return specimen.GetType();
    }

    private class NoInterceptorsSpecification : IRequestSpecification
    {
        public bool IsSatisfiedBy(object request)
        {
            var fi = request as FieldInfo;
            if (fi != null)
            {
                if (fi.Name == "__interceptors")
                    return false;
            }

            return true;
        }
    }
}

Diese Lösung bietet eine allgemeine Lösung für die Frage. Es wurde jedoch nicht ausführlich getestet, also würde ich gerne Feedback dazu bekommen.

Andere Tipps

Wahrscheinlich gibt es ein besseres Warum, aber das funktioniert:

var fixture = new Fixture();
var moq = new Mock<MyObject>() { DefaultValue = DefaultValue.Mock };
moq.Setup(m => m.GetSomeValue()).Returns(3);

fixture.Customize<MyObject>(c => c.FromFactory(() => moq.Object));

var anyMyObject = fixture.CreateAnonymous<MyObject>();

Assert.AreEqual(3, anyMyObject.GetSomeValue());
Assert.IsNotNull(anyMyObject.A);
//...

Anfangs habe ich versucht zu verwenden fixture.Register(() => moq.Object); Anstatt von fixture.Customize aber es registriert die Schöpferfunktion mit OmitAutoProperties() Es würde also nicht für Ihren Fall funktionieren.

Ab 3.20.0 können Sie verwenden AutoConfiguredMoqCustomization. Dadurch konfiguriert automatisch alle Mocks, sodass die Rückgabeteile ihrer Mitglieder durch Autofixure generiert werden.

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

var mock = fixture.Create<Mock<MyObject>>();

Assert.NotNull(mock.Object.A);
Assert.NotNull(mock.Object.B);
Assert.NotNull(mock.Object.C);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top