2012-04-05 2 views
1

Lassen Sie uns sagen, dass ich eine Reihe von Klassen, die wie etwas aussehen ...Unit Test stark gekoppelten Code in .net; Reflexion, um Mocks zu injizieren?

class Foo{ 
    private Bar highlyCoupled = new highlyCoupled(); 

    public bool DoTheThing(){ 
    return highlyCoupled.doesTheThing(); 
    } 
} 

Ist es möglich, Reflektion zu verwenden zu öffnen foo und injizieren eine Art von (Ente-punch eine korrektere Begriff sein kann) hochgekoppelt an Stelle von hochgekoppelt?

Was in dieser Situation über ...

class DoubleFoo : Foo{ 
    public bool DoTheOtherThing(){ 
    return DoTheThing(); 
    } 
} 

Kann die geerbte highlyCoupled ein Mock in seinen Platz eingesteckt habe?

Refactoring der Code, so dass keine Reflexion erforderlich ist, ist leider nicht möglich.

+1

Syntaxfehler in Zeile 2. –

+1

Ohne ein ernsthaftes Refactoring können Ihre Tests sehr brüchig sein. – jrummell

+0

Was fragen Sie? Können Sie die Reflektion verwenden, um private Mitglieder festzulegen? Ja, du kannst. Hast du Probleme damit? – cadrell0

Antwort

1

Da Sie Refactor mit einem Mock Framework nicht umgestalten können, könnte dies für Sie ein wenig einfacher machen. Zum Beispiel:

TypeMock:

var fakeType = Isolate.Fake.Instance<SomeType>(); 
ObjectState.SetField(fakeType, "_somePrivateField", myValue); 

Moq:

var fakeType = new Mock<SomeType>() 
fakeType.Protected().Setup<SomeType>("_somePrivateField").Returns(myValue); 

Um ehrlich zu sein, ich habe nicht wirklich versucht, dies mit Moq, aber ich denke, es wird tun, was Sie brauchen.

+0

Danke, das sieht nach der nützlichsten Antwort aus. Es schien keine sehr einzigartige Situation zu sein, zu sehen, dass es in einem Rahmen geantwortet hat. – MushinNoShin

+0

Welche Version von Moq hat die 'Protected()' Methode? Ich habe gerade Moq heruntergeladen und ich muss Mocks in private Felder injizieren, die sonst zur Laufzeit von MEF erstellt würden. – IAbstract

+0

Sollte in der neuesten Version gemäß der Dokumentation sein. http://code.google.com/p/moq/wiki/QuickStart#Miscellaneous – richk

0

Wenn Sie überhaupt nicht umgestalten können (make highlyCoupled geschützt), dann stecken Sie fest mit Reflexion. Dadurch können Sie den Wert highlyCoupled ohne Änderung festlegen.

+0

Intern würde auch funktionieren. – bryanbcook

0

Ich stimme Rob im Allgemeinen zu; Wenn Sie dies nicht umgestalten können, um die Abhängigkeit lockerer zu machen (zumindest erlauben Sie einer abgeleiteten Klasse wie einem Test-Proxy, den Standardwert zu überschreiben), dann ist Reflektion, um den Wert trotz seiner Sichtbarkeit zu setzen, die einzige Möglichkeit kann gehen.

Das absolute Minimum, was Sie tun können, ist, die Abhängigkeit zu schützen. Wenn dies möglich ist, jetzt oder zu einem beliebigen Zeitpunkt in der Zukunft, tut es:

class Foo{ 
    protected Bar highlyCoupled = new highlyCoupled(); 

    public bool DoTheThing(){ 
    return highlyCoupled.doesTheThing(); 
    } 
} 

... 

//in your test suite  
class FooTestProxy:Foo 
{ 
    public FooTestProxy(Bar testMock) 
    { 
     highlyCoupled = testMock; 
    } 
} 

//now when testing, instantiate your test proxy and pass it the mocked object 
1

Sie tatsächlich Reflexion und verspottet Art verwenden können, aber dieser Typ hat vom ursprünglichen Typ erben (FieldInfo.SetValue sonst fehlschlagen).

void Main() 
{ 
    var bar = new Bar(); 
    var type = typeof(Bar); 
    // Get the type and fields of FieldInfoClass. 
    var fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance); 
    fields[0].SetValue(bar, new FooMock()); // you can use new Foo() here too. 
    bar.Print(); 
} 

class Foo { 
    public int i = 0; 
} 

class FooMock : Foo { 
} 

class Bar { 
    private Foo foo = new Foo(); 

    public void Print() { 
     Console.WriteLine(i); 
    } 
}