Skip to content

Instantly share code, notes, and snippets.

@dtchepak
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dtchepak/8948799 to your computer and use it in GitHub Desktop.
Save dtchepak/8948799 to your computer and use it in GitHub Desktop.
Injection samples
/* 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 + "!";
}
}
/* 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);
}
/* 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);
}
/* 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);
}
/* 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);
}
/* 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