Last active
August 29, 2015 13:56
-
-
Save dtchepak/8948799 to your computer and use it in GitHub Desktop.
Injection samples
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Dependency */ | |
public class AnotherClass { | |
public virtual string DoSomething(string str1) { return str1.ToUpper(); } /* virtual so we can change/mock it. | |
* Alternatively use an interface, or abstract. */ | |
} | |
/* Class we want to test */ | |
public class MyClass { | |
public string str1; | |
public string MyMethod() | |
{ | |
var thatThing = new AnotherClass(); | |
string str2 = thatThing.DoSomething(str1); | |
// ... snip lots of fancy code that we really want to test | |
return str2 + "!"; | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Option 0: directly test the output we want, ignoring the details of how it gets it */ | |
[Test] | |
public void TestMyClassDirectlyAndIgnoreDependencyOnOtherClass() { | |
var myThing = new MyClass(); | |
myThing.str1 = "TestInput"; | |
string actualResult = myThing.MyMethod(); | |
Assert.AreEqual("TESTINPUT!", actualResult); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Option 1: pass dependency as explicit argument to the method we want to test. | |
* This makes it clear what `MyMethod` needs to do its job. It also gives us a seam | |
* to change `MyMethod`s behaviour by passing in another implementation of the dependency. | |
*/ | |
public class MyClass1 { | |
public string str1; | |
public string MyMethod(AnotherClass thatThing) { | |
string str2 = thatThing.DoSomething(str1); | |
// ... snip lots of fancy code that we really want to test | |
return str2 + "!"; | |
} | |
} | |
[Test] | |
public void UsingArgument() | |
{ | |
var thatThing = Substitute.For<AnotherClass>(); | |
thatThing.DoSomething("TestInput").Returns("ExpectedResult"); | |
var myThing = new MyClass1(); | |
myThing.str1 = "TestInput"; | |
string actualResult = myThing.MyMethod(thatThing); | |
Assert.AreEqual("ExpectedResult!", actualResult); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Option 2: expose dependency as field or property that can be set by external code. | |
* By default class functions normally. We just gain the option of switching `AnotherClass`. | |
*/ | |
public class MyClass2 { | |
public string str1; | |
public AnotherClass thatThing = new AnotherClass(); | |
public string MyMethod() { | |
string str2 = thatThing.DoSomething(str1); | |
// ... snip lots of fancy code that we really want to test | |
return str2 + "!"; | |
} | |
} | |
[Test] | |
public void UsingSetterInjection() | |
{ | |
var thatThing = Substitute.For<AnotherClass>(); | |
thatThing.DoSomething("TestInput").Returns("ExpectedResult"); | |
var myThing = new MyClass2(); | |
myThing.str1 = "TestInput"; | |
myThing.thatThing = thatThing; | |
string actualResult = myThing.MyMethod(); | |
Assert.AreEqual("ExpectedResult!", actualResult); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Option 3: inject dependency via constructor. | |
* Makes `MyClass3`s dependencies explicit. | |
* Can optionally provide a default constructor that picks the standard implementation. | |
*/ | |
public class MyClass3 | |
{ | |
private readonly AnotherClass thatThing; | |
public string str1; | |
public MyClass3(AnotherClass thatThing) { | |
this.thatThing = thatThing; | |
} | |
public string MyMethod() { | |
string str2 = thatThing.DoSomething(str1); | |
// ... snip lots of fancy code that we really want to test | |
return str2 + "!"; | |
} | |
} | |
[Test] | |
public void UsingConstructorInjection() | |
{ | |
var thatThing = Substitute.For<AnotherClass>(); | |
thatThing.DoSomething("TestInput").Returns("ExpectedResult"); | |
var myThing = new MyClass3(thatThing); | |
myThing.str1 = "TestInput"; | |
string actualResult = myThing.MyMethod(); | |
Assert.AreEqual("ExpectedResult!", actualResult); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Option 4: if each call to `MyMethod` requires a new instance of `AnotherClass`, | |
* we can inject a factory func and call it each time we need a new `AnotherClass`. | |
* Alternatives: use an explicit interface or class to hold the factory method. | |
* Can also provide a default constructor again here. | |
*/ | |
public class MyClass4 | |
{ | |
private readonly Func<AnotherClass> thatThingFactory; | |
public string str1; | |
public MyClass4(Func<AnotherClass> thatThingFactory) /* or IAnotherClassFactory interface or | |
* other class that can create instances */ | |
{ | |
this.thatThingFactory = thatThingFactory; | |
} | |
public string MyMethod() { | |
var thatThing = thatThingFactory(); | |
string str2 = thatThing.DoSomething(str1); | |
// ... snip lots of fancy code that we really want to test | |
return str2 + "!"; | |
} | |
} | |
[Test] | |
public void UsingInjectedFactory() { | |
var thatThingFactory = Substitute.For<Func<AnotherClass>>(); | |
thatThingFactory().DoSomething("TestInput").Returns("ExpectedResult"); | |
var myThing = new MyClass4(thatThingFactory); | |
myThing.str1 = "TestInput"; | |
string actualResult = myThing.MyMethod(); | |
Assert.AreEqual("ExpectedResult!", actualResult); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment