Wie zum Hohn eine Methode mit einem out-parameter?

Benutze ich eine Bibliothek, die verwendet out-Parameter in einer Funktion, die ich brauche, um mein test-code mit dieser Funktion.

So, versucht zu haben, verspottet zu meiner Rettung hier, über Moq, die habe ich mit in den rest des Projekts.

Frage

Ich weiß, es ist eine wall of text unten, so dass die Frage (im Voraus) ist:

  • Pro die Führung unten: Kann Moq mock ein Objekt mit einem Konstruktor, der Parameter erfordern, die nicht in der Regel als auf Ihre eigenen?
  • Ist das ein problem mit meinem test-code? Mit der Bibliothek? Mit der Validierung der Bibliothek?
  • Bin ich unter Verwendung Moq mit out-Parameter?
  • Wo ich noch Debuggen starten diese?

Update: Führt so Weit

Ich denke das ist ein Problem bei der spöttischen Seite mit Spott die IXLRow-Schnittstelle. Normalerweise erscheint ein XLRow wird nur instanziiert aus einer Arbeitsmappe und nie durch new XLRow() -- ist das ein Faktor?

Folgende test ist erfolgreich, wenn (Hinweis: mocks):

   [Fact]
    public void TryGetValueCanReturnTrueForVieldWithAnInteger_WhenAccessingFromRow()
    {
        var workbook = new XLWorkbook();
        workbook.Worksheets.Add("TestWS");
        var wb = workbook.Worksheet("TestWS");
        wb.Cell("A1").Value = "12345";

        //NOTE: Here we're referring to the row as part of an instantiated  
        //      workbook instead of Mocking it by itself
        int output;
        Assert.True(wb.Row(1).Cell("A").TryGetValue(out output));
    }

Den Code

Ausschnitt aus der Methode, wird ein mock ein gültiges Objekt():

//...other code that sets up other parts of the row correctly
int isAnyInt = 0; //I don't care about this value, only the true/false

//set this to false to true to mimic a row being a legitimate integer
mock.Setup(m => m.Cell("B").TryGetValue(out isAnyInt)).Returns(true);

xUnit-test-tests (happy path -- Bekommt ein mock eine gültige Zeile, und dann sorgt es geht Validierung. HINWEIS: Dieser test geht.

    [Fact]
    public void Validate_GivenValidRow_ReturnsValid()
    {
        var mockRow = TestHelper.GetMockValidInvoiceDetailsWorksheetRow();

        var validationResult = new InvoiceDetailsWorksheetRowValidator().Validate(mockRow.Object);
        Assert.True(validationResult.IsValid);
    }

einem xUnit-test (im Grunde, "hat der validator-Fehler mit einer Zelle, die nicht eine ganze Zahl?")
HINWEIS: Dieser test geht.

    [Fact]
    public void Validate_GivenNonNumericClaimantID_ReturnsInvalid()
    {
        int outint = 0;

        //Get a mock of a valid row
        var mockRow = TestHelper.GetMockValidInvoiceDetailsWorksheetRow();

        //change the TryGetValue result to false
        mockRow.Setup(m => m.Cell("B").TryGetValue(out outint)).Returns(false);

        var validationResult = new InvoiceDetailsWorksheetRowValidator().Validate(mockRow.Object);
        Assert.False(validationResult.IsValid);
        Assert.Equal("ClaimantID column value is not a number.", validationResult.Errors.First().ErrorMessage);
    }

Den validator (mit FluentValidation):

public class InvoiceDetailsWorksheetRowValidator : AbstractValidator<IXLRow>
{
    public InvoiceDetailsWorksheetRowValidator()
    {
        RuleFor(x => x.Cell("B"))
            .Must(BeAnInt).WithMessage("ClaimantID column value is not a number.")
            .OverridePropertyName("ClaimantIDColumn");

    }

    private bool BeAnInt(IXLCell cellToCheck)
    {
        int result;
        var successful = cellToCheck.TryGetValue(out result);
        return successful;
    }
}

Referenz, der die Methode aus der Bibliothek:

    public Boolean TryGetValue<T>(out T value)
    {
        var currValue = Value;

        if (currValue == null)
        {
            value = default(T);
            return true;
        }

        bool b;
        if (TryGetTimeSpanValue(out value, currValue, out b)) return b;

        if (TryGetRichStringValue(out value)) return true;

        if (TryGetStringValue(out value, currValue)) return true;

        var strValue = currValue.ToString();
        if (typeof(T) == typeof(bool)) return TryGetBasicValue<T, bool>(out value, strValue, bool.TryParse);
        if (typeof(T) == typeof(sbyte)) return TryGetBasicValue<T, sbyte>(out value, strValue, sbyte.TryParse);
        if (typeof(T) == typeof(byte)) return TryGetBasicValue<T, byte>(out value, strValue, byte.TryParse);
        if (typeof(T) == typeof(short)) return TryGetBasicValue<T, short>(out value, strValue, short.TryParse);
        if (typeof(T) == typeof(ushort)) return TryGetBasicValue<T, ushort>(out value, strValue, ushort.TryParse);
        if (typeof(T) == typeof(int)) return TryGetBasicValue<T, int>(out value, strValue, int.TryParse);
        if (typeof(T) == typeof(uint)) return TryGetBasicValue<T, uint>(out value, strValue, uint.TryParse);
        if (typeof(T) == typeof(long)) return TryGetBasicValue<T, long>(out value, strValue, long.TryParse);
        if (typeof(T) == typeof(ulong)) return TryGetBasicValue<T, ulong>(out value, strValue, ulong.TryParse);
        if (typeof(T) == typeof(float)) return TryGetBasicValue<T, float>(out value, strValue, float.TryParse);
        if (typeof(T) == typeof(double)) return TryGetBasicValue<T, double>(out value, strValue, double.TryParse);
        if (typeof(T) == typeof(decimal)) return TryGetBasicValue<T, decimal>(out value, strValue, decimal.TryParse);

        if (typeof(T) == typeof(XLHyperlink))
        {
            XLHyperlink tmp = GetHyperlink();
            if (tmp != null)
            {
                value = (T)Convert.ChangeType(tmp, typeof(T));
                return true;
            }

            value = default(T);
            return false;
        }

        try
        {
            value = (T)Convert.ChangeType(currValue, typeof(T));
            return true;
        }
        catch
        {
            value = default(T);
            return false;
        }
    }

Das Problem

Den ersten test bestanden. Aber wenn ich diesen test ausführen, schlägt fehl:

   [Fact]
   public void Validate_GivenNonNumericInvoiceNumber_ReturnsInvalid()
    {
        int outint = 0; //I don't care about this value

        //Get a mock of a valid worksheet row
        var mockRow = TestHelper.GetMockValidInvoiceDetailsWorksheetRow();

        mockRow.Setup(m => m.Cell("E").TryGetValue(out outint)).Returns(false);

        //Validates & asserts
        var validationResult = new InvoiceDetailsWorksheetRowValidator().Validate(mockRow.Object);
        Assert.False(validationResult.IsValid);

        //Placed here to ensure it's the only error message. This is where it fails.
        Assert.Equal("InvoiceNumber column value is not a number.",validationResult.Errors.First().ErrorMessage);
    }

Aber es muss nicht daran scheitern, dass die Validierung noch nicht umgesetzt wurden -- es schlägt fehl, da das andere Element ist ungültig ersten, auch wenn ich fahre es, dass man eine gültige mock -- das gleiche gilt mock, die tests besteht, sonst.

Die Nachricht genau ist:

Geltend zu machen.Gleich ( - ) Fehler

Position: Erste Unterschied liegt an position 0

Erwartet: InvoiceNumber Spalte der Wert keine Zahl ist.

Aktuell: ClaimantID Spalte der Wert keine Zahl ist.

Ich würde erwarten:

  • Es funktioniert auf die gleiche Weise die anderen test gearbeitet, oder
  • Für den glücklichen Weg, um auch scheitern.

Aber wenn die happy-Pfad (z.B. gültige mock) geht, aber der test schlägt fehl, da die Methode ungültig ist (der gleiche, geht die gleiche Validierung als Teil der "gültigen" mock)...es lässt mich völlig verwirrt.

Referenz

  • Ähnliche Frage hier.
InformationsquelleAutor SeanKilleen | 2013-10-02
Schreibe einen Kommentar