Laden...

Moq-Framework: wie geht Weakmatching?

Erstellt von spike24 vor 12 Jahren Letzter Beitrag vor 12 Jahren 2.013 Views
S
spike24 Themenstarter:in
443 Beiträge seit 2008
vor 12 Jahren
Moq-Framework: wie geht Weakmatching?

Hallo Ihr,

Ich glaube es heist Weakmatching, Ich möchte das Parameter nur teilweise Matchen.

Ich habe eine Klasse die als Identifier einen Guid erstellt.
Guid ProcessArguments.Identifier;
Diese Klasse hat auch noch eine zweite Property
List<string> ProcessArguments.Strings

In meiner TestKlasse bereichte ich eine Instance auf um sie der Method Setup des Moq frameworks

ProcessArgument arg = new ProcessArgument();
// der Identifier wird im ctor zugewiesen (eine Guid erstellt)
arg.Strings.Add("test");

Die Methode die ich testen möchte erstellt ebenfalls ein ProcessArgument,
klarerweise mit einer anderen Guid.

Wie kann ich nun das Moq framework aufsetzten dass nur die Gleichheit der Property Strings überprüft wird?

Ich verbringe leider schon realtive viel Zeit damit, wäre net wenn Ihr mir dabei helfen könntet!?

mbg
Robert Rossegger

Noch ein bisschen Code, zum zeigen was ich habe, aber leider nicht funktioniert.

mTestClassMock.Setup(mock => mock.MethodToTest(It.Is<ProcessArgument>(argument => EqualsProcessArgument(argument, processModificationEventArgs))
)).Returns(bla));


private static bool EqualsProcessArgument(ProcessArgument processModificationArgument, ProcessArgument processModificationArgumento)
{
// wird nie aufgerufen!
  return true;
}

http://code.google.com/p/moq/wiki/QuickStart
diese seite sah für mich am richtigsten aus, allerdings habe ich nicht mal annähernd das gleiche Verhalten.

Moq Version:
4.0.10827.0

// Edit Fehler behoben, danke fürs genaue lesen

mbg
Rossegger Robert
mehr fragen mehr wissen

Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo spike24,

wenn ich dich richtig verstanden habe kannst du mit Callbacks arbeiten und dort das Argument behandeln.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

1.361 Beiträge seit 2007
vor 12 Jahren

Hi spike24,
1.Vielleicht ist es nur ein Fehler für die Aufbereitung hier fürs Forum, aber beachte:

EqualsProcessModificationArgument != EqualsProcessArgument

Du rufst die untere Methode überhaupt nicht. 1.Regel für Unit-Tests: Abhängigkeiten zur Umgebung wegmocken! Deine Klasse ist anscheinend hart an einen bestimmen GUID-Generator gekoppelt.
Wenn du diese Kopplung loser gestaltest, also ein Interface für GUID-Generatoren erstellst, und deinen ProcessArguments einen solchen GUID-Generator mitgibst. (vielleicht auch als statisches feld) Dann kannst du die GUID-Erzeugung innerhalb der Unit-Tests wegmocken und dort fest definierte, immer selbe GUIDs zurückgeben.

beste Grüße
zommi

S
spike24 Themenstarter:in
443 Beiträge seit 2008
vor 12 Jahren

@gfoidl
Ja, ich denke Du hast mich richtig verstanden, allerdings probiere ich schon ewig damit herum und schaffe es nicht um die Burg.
Die Haltepunkte die ich da setzte werden nicht mal angesprungen. Also wenn etwas falsches geliefert werden würde wäre es ja noch ok, aber es wird nicht mal was aufgerufen.

Hier ein OriginalCode (nicht aufbereitet) der den Callback nicht aufruft:

mObjectStoreServerMock.Setup(mock => mock.ProcessModification(
It.IsAny<ProcessModificationArgument>()))
.Callback<ProcessModificationArgument>(argument => EqualsProcessModificationArgument(argument, processModificationEventArgs)
).Returns(TestResults.LoadProcessModificationResult(processModificationEventArgs));

@zoomi
war ein Fehler im Aufbereiten, habs schon ausgebessert.

Generell wollte ich sowas vermeiden, nur wegen dem Testen ein neues Interface einführen. (Oder ProcessIdentifierFactory (liefert die Guid))
Vorallem da das Ding das fast public sein müsste damit ich auch von den Tests darauf zugreifen müsste. Und das schmeckt mir dann garnicht.

mbg
Rossegger Robert
mehr fragen mehr wissen

Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo spike24,

Generell wollte ich sowas vermeiden, nur wegen dem Testen ein neues Interface einführen.

Das ist aber in der Regel gutes Design 😃

Zum Problem: so wie das Setup ist wird das Return "eager" ausgeführt, also sofort beim Initialisieren und danach nciht mehr. Wenn du es "lazy" machts sollte es passen.


.Returns(() => ....);

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

S
spike24 Themenstarter:in
443 Beiträge seit 2008
vor 12 Jahren

Ich hab das Retrun umgebaut, jetzt wird sie garnicht mehr aufgerufen !?!
Finde ich jetzt aber auch schräg.
Generell hatte ich aber das Problem dass EqualsProcessModificationArgument nicht aufgerufen wird.

Ist ein gutes Design, einen privat Spass einer Klasse auslagern nur zum testen?
Hmm widerstrebt mir irgendwie, vorallem da es ja zum Mocken gehen sollte

// EDIT:
gerade gefunden in Moq.Mock<T> - how to setup a method that takes an expression:

However you are coming up against one of Moq's shortcomings. You would want to put an actual expression there instead of using It.IsAny, but Moq doesn't support setting up methods that take expressions with specific expressions (it's a difficult feature to implement). The difficulty comes from having to figure out whether two expressions are equivalent.

Heist das, das geht nicht?

mbg
Rossegger Robert
mehr fragen mehr wissen

Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen

A
350 Beiträge seit 2010
vor 12 Jahren

Es ist immer gutes Design gegen Interfaces zu programmieren 😉

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo spike24,

wenn der Mock richtig konfiguriert wird und es trotzdem nicht aufgerufen wird dann wird es wahrscheinlich von der Methode die zu testen ist nicht aufgerufen. Prüfe dort mal.

Ist ein gutes Design, einen privat Spass einer Klasse auslagern nur zum testen?

Da es nicht das Thema ist nur kurz: Kommt darauf an 😉
Wenn damit Single-Reponsibility erreicht wird ja. Beispiel:


public interface IGuidGenerator {...}

public class DortWoEsVerwendetWerdenSoll
{
    private readonly IGuidGenerator _guidGenerator;

    public DortWoEsVerwendetWerdenSoll(IGuidGenerator guidGenerator)
    {
        _guidGenerator = guidGenerator;
    }
}

So kann der GuidGenerator extra getestet werden und auch die Klasse DortWoEsVerwendetWerdenSoll indem IGuidGenerator gemockt wird.
Sonst kann privates (das eindeutig zur Funktionalität der Klasse gehört) auch über die public Member getestet werden. Wenn es nicht dazu gehört gehört es auch in eine eigene Klasse.

Für weitere Infos darüber suche im Forum, das wurde schon einige male besprochen.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

S
417 Beiträge seit 2008
vor 12 Jahren

Hallo,

prüf doch erstmal, ob der Aufurf überhaupt stattfindet.

mTestClassMock.Setup(mock => mock.MethodToTest(It.IsAny<ProcessArgument>())).Returns(bla);
...

mTestClassMock.VerifyAll();
S
spike24 Themenstarter:in
443 Beiträge seit 2008
vor 12 Jahren

@Ahrimaan
Alleine wenn jemand bei Patterns 'immer' sagt stelle ich es in Frage.
Es ist richtig gegen interfaces zu programmieren hat definitv einen Sinn, allerdings kenne ich auch das Gegenteil. Bei uns in der Firma programmieren wir gegen soviele Interfaces (weil dann können wir alles austauschen und customizen) dass sich keiner mehr auskennt was eigentlich abgeht und das erste Interface, bzw die Klasse dazu sieht noch immer gleich aus wie vor drei Jahren wie ich es programmiert habe, also nix mit austauschen. Und einen haben wir, der implementier ein Interface wenn es techniss einen Sinn ergibt, und ich kann Dir sagen niemand versteht seinen Code.

@gfoidl
Das SRP ist mir im Grund klar und ich gehe auch darauf ein wenn ich etwas entwickle. Allerdings mache ich in diesem Bereich wegen der Lesbarkeit und wartbarkeit Abstriche. eine ProcessModificationIdentifier hinter einem Interface mit IOC und DI bereitstellen ist schwieriger zu entziffern als
ProcessModificationIdentifier identifier = new ProcessModiificationIdentifier();
(da drin ist die Guid), ein klick go to definition und ich sehe die Klasse, sonst muss ich das interface suche und dann kucken wer das alles implementiert.
Ich verstehe das Prinzip, aber wenn es das Verständnis des Codes erschwert gehe ich gerne Kompromisse ein.

Und an Dich geht auch die Medailie fürs helfen, und ich bekomme wiedereinmal die Goldene Ananas. Offensichtlich habe ich beim herumprobieren in den letzten 3 Wochen irgendwas kaputt gemacht, jetzt habe ich es nun gerichtet. Jetzt kommt was falsches aber es wird wenigstens aufgerufen.

@Sarc
Du hast auch in die richtige Kerbe geschlagen.

mbg
Rossegger Robert
mehr fragen mehr wissen

Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen