MSDN Magazine - December 2008 - (Page 40) up the database for those test inputs on each test run, but there’s an easier way. Let’s just use a fake database that can be more easily controlled in testing scenarios by using the Repository pattern to mediate between the application’s domain model and the data access services. Figure 3 Fake Database from IRepository public class InMemoryRepository : IRepository { private readonly Cache _types; private MockUnitOfWork _lastUnitOfWork; public InMemoryRepository() { _types = new Cache (type => { Type listType = typeof(List ).MakeGenericType(type); return Activator.CreateInstance(listType); }); } private IList listFor () { return (IList )_types.Get(typeof(T)); } public T Find (long id) where T : Entity { return listFor ().FirstOrDefault(t => t.Id == id); } public void Delete (T target) { listFor ().Remove(target); } public T[] Query (Expression<Func > where) { var query = from item in listFor () select item; return query.Where(where.Compile()).ToArray(); } public void Save (T target) { listFor ().Add(target); } My team has consistently chosen to use a Repository pattern with an IRepository interface: public interface Irepository { T Find (long id) where T : Entity; void Delete (T target); T[] Query (Expression<System.Func > where); void Save (T target); } } Figure 4 Test that Simulates a Database State [Test] public void find_the_user_by_user_name_and_password() { // Set up an InMemoryRepository with a User InMemoryRepository repository = new InMemoryRepository(); User user = new User(){UserId = "jeremy"}; user.ResetPassword("thePassword"); // the password is hashed repository.Save(user); // Construct a new instance of SecurityDataService using the // InMemoryRepository from above SecurityDataService service = new SecurityDataService(repository); service.Authenticate("jeremy", "wrong").ShouldBeFalse(); service.Authenticate("jeremy", "thePassword").ShouldBeTrue(); service.Authenticate("wrong", "thePassword").ShouldBeFalse(); service.Authenticate("wrong", "and wrong").ShouldBeFalse(); The real implementation of Repository uses NHibernate and LINQ for NHibernate to transfer information between the Entity objects and the database tables. In unit testing scenarios, all you really care about is that an Entity was saved, deleted, or available from this IRepository interface because that’s all that the rest of the application knows about. For testing, you can create a known database state by using an implementation of IRepository (see Figure 3) that simply stores objects in memory and uses LINQ-to-Objects instead of LINQ for NHibernate for querying. In unit tests, you construct objects that depend on IRepository with an instance of the InMemoryRepository that was set up with the desired data. Figure 4 shows a sample unit test that uses InMemoryRepository to simulate a database state. The sample tests the functionality of the SecurityDataService class (see Figure 5). Internally, it needs to query an IRepository for the existence of a user with a username and password. In the real application, the SecurityDataService uses the NHibernate Repository object that accesses the database. But in testing you can happily substitute a fake Repository that can easily be controlled to more quickly simulate multiple test cases. You can only do this type of substitution with fake objects if the classes that use IRepository only depend on the declared interface of IRepository. If the classes that use IRepository depend even indirectly on the fact that the normal IRepository does NHibernate-specific things, you won’t be able to cleanly substitute the fake object. Fake objects, such as stubs or mocks, are a huge advantage for doing emergent or continuous design by allowing you to build, and even design, a system incrementally by standing in for services that you haven’t yet created. Almost every project I work on contains at least one feature that requires the application to send automated e-mail notifications to the user depending on some sort of action and state in the system. But I most definitely do not want my application code getting hung up with e-mail functionality. I like to wrap up e-mail functionality by using the Gateway pattern. In the Gateway pattern, an object encapsulates access to an external system or resource. I want to pull every single piece of code it takes to send e-mails, including SMTP-type configuration, and hide it away from the rest of my code inside an IEmailGateway object, like this: public class EmailMessage { public string Body { get; set; } public string[] To { get; set; } } public interface IEmailGateway { void SendChangeStatusEmailTo(WorkflowState workflow, User owner); } The Gateway Pattern } Figure 5 Class to Be Tested public class SecurityDataService : ISecurityDataService { private readonly IRepository _repository; // The IRepository dependency is set up via Constructor Injection // In our real application, Both the real NHibernateRepository // and the SecurityDataService would be constructed by // an Inversion of Control container public SecurityDataService(IRepository repository) { _repository = repository; } public bool Authenticate(string username, string password) { return _repository.FindBy (u => u.UserId == username && u.Password == User.HashPassword(password)) != null; } } 40 msdn magazine Patterns in Practice
Table of Contents Feed for the Digital Edition of MSDN Magazine - December 2008 MSDN Magazine - December 2008 Contents Toolbox CLR Inside Out Advanced Basics Cutting Edge Patterns In Practice Team System Real-World WF Visual Studio OBA Tools SOA Data Access Geneva Framework Test Run Foundations Windows With C++ Going Places End Bracket MSDN Magazine - December 2008 MSDN Magazine - December 2008 - (Page Intro) MSDN Magazine - December 2008 - Contents (Page Cover1) MSDN Magazine - December 2008 - Contents (Page Cover2) MSDN Magazine - December 2008 - Contents (Page 1) MSDN Magazine - December 2008 - Contents (Page 2) MSDN Magazine - December 2008 - Contents (Page 3) MSDN Magazine - December 2008 - Contents (Page 4) MSDN Magazine - December 2008 - Contents (Page 5) MSDN Magazine - December 2008 - Contents (Page 6) MSDN Magazine - December 2008 - Contents (Page 7) MSDN Magazine - December 2008 - Contents (Page 8) MSDN Magazine - December 2008 - Contents (Page 9) MSDN Magazine - December 2008 - Contents (Page 10) MSDN Magazine - December 2008 - Toolbox (Page 11) MSDN Magazine - December 2008 - Toolbox (Page 12) MSDN Magazine - December 2008 - Toolbox (Page 13) MSDN Magazine - December 2008 - Toolbox (Page 14) MSDN Magazine - December 2008 - CLR Inside Out (Page 15) MSDN Magazine - December 2008 - CLR Inside Out (Page 16) MSDN Magazine - December 2008 - CLR Inside Out (Page 17) MSDN Magazine - December 2008 - CLR Inside Out (Page 18) MSDN Magazine - December 2008 - CLR Inside Out (Page 19) MSDN Magazine - December 2008 - CLR Inside Out (Page 20) MSDN Magazine - December 2008 - CLR Inside Out (Page 21) MSDN Magazine - December 2008 - Advanced Basics (Page 22) MSDN Magazine - December 2008 - Advanced Basics (Page 23) MSDN Magazine - December 2008 - Advanced Basics (Page 24) MSDN Magazine - December 2008 - Advanced Basics (Page 25) MSDN Magazine - December 2008 - Advanced Basics (Page 26) MSDN Magazine - December 2008 - Advanced Basics (Page 27) MSDN Magazine - December 2008 - Advanced Basics (Page 28) MSDN Magazine - December 2008 - Cutting Edge (Page 29) MSDN Magazine - December 2008 - Cutting Edge (Page 30) MSDN Magazine - December 2008 - Cutting Edge (Page 31) MSDN Magazine - December 2008 - Cutting Edge (Page 32) MSDN Magazine - December 2008 - Cutting Edge (Page 33) MSDN Magazine - December 2008 - Cutting Edge (Page 34) MSDN Magazine - December 2008 - Cutting Edge (Page 35) MSDN Magazine - December 2008 - Cutting Edge (Page 36) MSDN Magazine - December 2008 - Patterns In Practice (Page 37) MSDN Magazine - December 2008 - Patterns In Practice (Page 38) MSDN Magazine - December 2008 - Patterns In Practice (Page 39) MSDN Magazine - December 2008 - Patterns In Practice (Page 40) MSDN Magazine - December 2008 - Patterns In Practice (Page 41) MSDN Magazine - December 2008 - Patterns In Practice (Page 42) MSDN Magazine - December 2008 - Patterns In Practice (Page 43) MSDN Magazine - December 2008 - Team System (Page 44) MSDN Magazine - December 2008 - Team System (Page 45) MSDN Magazine - December 2008 - Team System (Page 46) MSDN Magazine - December 2008 - Team System (Page 47) MSDN Magazine - December 2008 - Team System (Page 48) MSDN Magazine - December 2008 - Team System (Page 49) MSDN Magazine - December 2008 - Team System (Page 50) MSDN Magazine - December 2008 - Team System (Page 51) MSDN Magazine - December 2008 - Real-World WF (Page 52) MSDN Magazine - December 2008 - Real-World WF (Page 53) MSDN Magazine - December 2008 - Real-World WF (Page 54) MSDN Magazine - December 2008 - Real-World WF (Page 55) MSDN Magazine - December 2008 - Real-World WF (Page 56) MSDN Magazine - December 2008 - Real-World WF (Page 57) MSDN Magazine - December 2008 - Real-World WF (Page 58) MSDN Magazine - December 2008 - Real-World WF (Page 59) MSDN Magazine - December 2008 - Real-World WF (Page 60) MSDN Magazine - December 2008 - Real-World WF (Page 61) MSDN Magazine - December 2008 - Visual Studio OBA Tools (Page 62) MSDN Magazine - December 2008 - Visual Studio OBA Tools (Page 63) MSDN Magazine - December 2008 - Visual Studio OBA Tools (Page 64) MSDN Magazine - December 2008 - Visual Studio OBA Tools (Page 65) MSDN Magazine - December 2008 - Visual Studio OBA Tools (Page 66) MSDN Magazine - December 2008 - Visual Studio OBA Tools (Page 67) MSDN Magazine - December 2008 - Visual Studio OBA Tools (Page 68) MSDN Magazine - December 2008 - Visual Studio OBA Tools (Page 69) MSDN Magazine - December 2008 - Visual Studio OBA Tools (Page 70) MSDN Magazine - December 2008 - Visual Studio OBA Tools (Page 71) MSDN Magazine - December 2008 - SOA Data Access (Page 72) MSDN Magazine - December 2008 - SOA Data Access (Page 73) MSDN Magazine - December 2008 - SOA Data Access (Page 74) MSDN Magazine - December 2008 - SOA Data Access (Page 75) MSDN Magazine - December 2008 - SOA Data Access (Page 76) MSDN Magazine - December 2008 - SOA Data Access (Page 77) MSDN Magazine - December 2008 - SOA Data Access (Page 78) MSDN Magazine - December 2008 - SOA Data Access (Page 79) MSDN Magazine - December 2008 - SOA Data Access (Page 80) MSDN Magazine - December 2008 - SOA Data Access (Page 81) MSDN Magazine - December 2008 - Geneva Framework (Page 82) MSDN Magazine - December 2008 - Geneva Framework (Page 83) MSDN Magazine - December 2008 - Geneva Framework (Page 84) MSDN Magazine - December 2008 - Geneva Framework (Page 85) MSDN Magazine - December 2008 - Geneva Framework (Page 86) MSDN Magazine - December 2008 - Geneva Framework (Page 87) MSDN Magazine - December 2008 - Geneva Framework (Page 88) MSDN Magazine - December 2008 - Geneva Framework (Page 89) MSDN Magazine - December 2008 - Geneva Framework (Page 90) MSDN Magazine - December 2008 - Test Run (Page 91) MSDN Magazine - December 2008 - Test Run (Page 92) MSDN Magazine - December 2008 - Test Run (Page 93) MSDN Magazine - December 2008 - Test Run (Page 94) MSDN Magazine - December 2008 - Test Run (Page 95) MSDN Magazine - December 2008 - Test Run (Page 96) MSDN Magazine - December 2008 - Test Run (Page 97) MSDN Magazine - December 2008 - Test Run (Page 98) MSDN Magazine - December 2008 - Test Run (Page 99) MSDN Magazine - December 2008 - Test Run (Page 100) MSDN Magazine - December 2008 - Foundations (Page 101) MSDN Magazine - December 2008 - Foundations (Page 102) MSDN Magazine - December 2008 - Foundations (Page 103) MSDN Magazine - December 2008 - Foundations (Page 104) MSDN Magazine - December 2008 - Foundations (Page 105) MSDN Magazine - December 2008 - Foundations (Page 106) MSDN Magazine - December 2008 - Foundations (Page 107) MSDN Magazine - December 2008 - Foundations (Page 108) MSDN Magazine - December 2008 - Windows With C++ (Page 109) MSDN Magazine - December 2008 - Windows With C++ (Page 110) MSDN Magazine - December 2008 - Windows With C++ (Page 111) MSDN Magazine - December 2008 - Windows With C++ (Page 112) MSDN Magazine - December 2008 - Going Places (Page 113) MSDN Magazine - December 2008 - Going Places (Page 114) MSDN Magazine - December 2008 - Going Places (Page 115) MSDN Magazine - December 2008 - Going Places (Page 116) MSDN Magazine - December 2008 - Going Places (Page 117) MSDN Magazine - December 2008 - Going Places (Page 118) MSDN Magazine - December 2008 - Going Places (Page 119) MSDN Magazine - December 2008 - End Bracket (Page 120) MSDN Magazine - December 2008 - End Bracket (Page Cover3) MSDN Magazine - December 2008 - End Bracket (Page Cover4)
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.