Skip to content

Instantly share code, notes, and snippets.

@CopperStarSystems
Created September 27, 2016 19:48
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 CopperStarSystems/98f8038744e433acaf8cc8d947b8b53d to your computer and use it in GitHub Desktop.
Save CopperStarSystems/98f8038744e433acaf8cc8d947b8b53d to your computer and use it in GitHub Desktop.
C# class after refactoring to improve testability
// This is an example class illustrating some common patterns
// to simplify unit testing
public class MuchEasierToTest{
// Changed to ISomeModel so we can inject a mock model during testing
ISomeModel model;
IPath path;
// Update constructor to take ISomeOtherDependency so we can inject a mock instance
// during testing. Same thing for ISomeModelFactory and IPath.
public ReallyHardToTest(ISomeOtherDependency otherDependency, ISomeModelFactory someModelFactory, IPath path){
// Invoke the method on our factory instead of directly creating a Model instance
// Our tests can now verify that a new ISomeModel instance is created in the constructor
model = someModelFactory.Create();
// Because we are programming against ISomeOtherDependency, we can verify that this
// method is invoked at test time.
otherDependency.DoSomething();
this.path = path;
}
public void SetFilename(string fileName){
// Invoke method on injected IPath instance instead of the
// static Path class.
model.Filename = path.GetFileName(fileName);
}
}
// This code implements a wrapper around the static Path class.
// The interface allows us to inject a mock IPath instance at
// test time (for example when testing the MuchEasierToTest class).
public interface IPath{
string GetFileName(string fileName);
}
public class PathImpl : IPath {
public string GetFileName(string fileName){
return Path.GetFileName(fileName);
}
}
// Introducing an interface enables us to mock SomeModel in tests
public interface ISomeModel{
string FileName{get;set;}
}
// Same concrete SomeModel type as in original file.
public class SomeModel : ISomeModel{
public string FileName{get;set;}
}
// Introducing a factory interface enables us to verify
// that creation logic is invoked and also to control
// the result of creation by returning a mock instance
public interface ISomeModelFactory{
ISomeModel Create();
}
// Notice that the factory class only has one responsibility:
// To give us a new instance of a type implementing ISomeModel.
// At test time, we will be able to inject a mock factory instance
// and control what it returns, giving us better control over
// our test coverage.
public class SomeModelFactory : ISomeModelFactory{
public ISomeModel Create(){
return new SomeModel();
}
}
// Introducing an interface enables us to mock SomeOtherDependency in tests
public interface ISomeOtherDependency{
void DoSomething();
}
// Same concrete SomeOtherDependency type as original file
public class SomeOtherDependency : ISomeOtherDependency{
public void DoSomething(){
// Just here for illustration.
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment