Skip to content

Instantly share code, notes, and snippets.

@micahlmartin
Last active December 15, 2015 04:08
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 micahlmartin/5198865 to your computer and use it in GitHub Desktop.
Save micahlmartin/5198865 to your computer and use it in GitHub Desktop.
Example of code that's easier to test and code that's harder to test. Instance vs. Static.
// Acceptable
// Use of IoC required now in two places: UserService and CoolService
public class UserRepository
{
public User GetUserByID(long userID)
{
//Get user from database
}
public void Save(User user)
{
//Save user to database
}
}
public class UserService
{
private UserRepository _userRepository;
public UserService(UserRepository userRepository)
{
_userRepository = userRepository
}
public User GetUserByID(long userID)
{
return _userRepository.GetUserByID(userID);
}
public void Save(User user)
{
_userRepository.Save(user);
}
}
public class CoolService
{
private UserService _userService;
public SomethingCool(UserService userService)
{
_userService = userService;
}
public void MakeUserCool(long userID)
{
var user = _userService.GetUserByID(userID)
user.IsCool = true;
_userService.Save(user);
}
}
[TestFixture]
public class TestCoolService
{
[Test]
[ExpectedException(typeof(Exception))]
public void TestUserIsCool
{
var userRepositoryMock = new UserRepositoryMock();
var userService = new UserService(userRepositoryMock);
var coolService = new CoolService(userService);
//This will throw an exception if user is not cool
coolService.MakeUserCool(1);
}
private class UserRepositoryMock
{
public override User GetUserByID(long userID)
{
return new User { UserID = userID, IsCool = false };
}
public override void Save(User user)
{
if(!user.IsCool)
throw new Exception("Expected user to be cool");
}
}
}
// Bad
// IoC required at the method level and still needed at the CoolService level.
// Too many extra hoops to jump through and test
public class UserService
{
public static User GetUserByID(long userID)
{
return GetUserByID(userID, new UserService());
}
public static User GetUserByID(long userID, UserService userService)
{
return userService.GetUserByID(userID);
}
public static void Save(User user)
{
Save(user, new UserService());
}
public static void Save(User user, UserService userService)
{
userService.Save(user);
}
}
public class CoolService
{
private UserService _userService;
public CoolService(UserService userService)
{
_userService = userService;
}
public void MakeUserCool(long userID)
{
var user = UserService.GetUserByID(userID, _userService)
user.IsCool = true;
UserService.Save(user, _userService);
}
}
[TestFixture]
public class TestCoolService
{
[Test]
[ExpectedException(typeof(Exception))]
public void TestUserIsCool
{
var userServiceMock = new UserServiceMock();
var coolService = new CoolService(userServiceMock);
//This will throw an exception if user is not cool
coolService.MakeUserCool(1);
}
private class UserServiceMock
{
public override User GetUserByID(long userID)
{
return new User { UserID = userID, IsCool = false };
}
public override void Save(User user)
{
if(!user.IsCool)
throw new Exception("Expected user to be cool");
}
}
}
// Best
// Use of IoC is relegated only to the calling class.
// Only 1 point of indirection
public class UserService
{
public virtual User GetUserByID(long userID)
{
//Get user from database
}
public virtual void Save(User user)
{
//Save user to database
}
}
public class CoolService
{
private UserService _userService;
public SomethingCool(UserService userService)
{
_userService = userService;
}
public void MakeUserCool(long userID)
{
var user = _userService.GetUserByID(userID)
user.IsCool = true;
_userService.Save(user);
}
}
[TestFixture]
public class TestCoolService
{
[Test]
[ExpectedException(typeof(Exception))]
public void TestUserIsCool
{
var userServiceMock = new UserServiceMock();
var coolService = new CoolService(userServiceMock);
//This will throw an exception if user is not cool
coolService.MakeUserCool(1);
}
private class UserServiceMock
{
public override User GetUserByID(long userID)
{
return new User { UserID = userID, IsCool = false };
}
public override void Save(User user)
{
if(!user.IsCool)
throw new Exception("Expected user to be cool");
}
}
}
// Best 2
// Use of IoC is relegated only to the calling class.
// Injection of dependency is through an instance variable rather than through the constructor
public class UserService
{
public virtual User GetUserByID(long userID)
{
//Get user from database
}
public virtual void Save(User user)
{
//Save user to database
}
}
public class CoolService
{
public UserService UserService { get; set; }
public void MakeUserCool(long userID)
{
var user = UserService.GetUserByID(userID)
user.IsCool = true;
UserService.Save(user);
}
}
[TestFixture]
public class TestCoolService
{
[Test]
[ExpectedException(typeof(Exception))]
public void TestUserIsCool
{
var userServiceMock = new UserServiceMock();
var coolService = new CoolService();
coolService.UserService = userServiceMock;
//This will throw an exception if user is not cool
coolService.MakeUserCool(1);
}
private class UserServiceMock
{
public override User GetUserByID(long userID)
{
return new User { UserID = userID, IsCool = false };
}
public override void Save(User user)
{
if(!user.IsCool)
throw new Exception("Expected user to be cool");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment