Clean Code Developer Here I share my ideas about software craftsmanship.
Walkthrough: ADO.NET Unit Testable Repository Generator
On 27, Okt. 2010 | inClean Code Developer | vonJohannes Hoppe
This walkthrough is going to show you the usage of my new T4 template called „ADO.NET Unit Testable Repository Generator“.
Table of contents:
- Step 1: Create the Entity Data Model
- Step 2: Add the Code Generation Item
- Step 3: Use the Repository
- Step 4: Use the Unit Test
- Step 5: Download the sample solution
My demo implements a small repository to manage simple text-snippeds in the database. I will start with an empty ASP.NET MVC 2 project. Any other type would work, too.
Step 1: Create the Entity Data Model
Now we are going to add an Entity Data Model (EDMX) file.
- Right click on Models, select Add > New Item…
- and choose ADO.NET Entity Data Model. I recommend the Name: “WebNoteModel.edmx”
- Generate it from the database,
- and create a working connection string with the help of the wizard.
- Please be sure that you select a meaningful Entity Container Name. This name will be used for the generated files, too. I chose “FileStore”.
- Select your tables and Pluralize or singularize generated object names (select the checkbox)
- and chose a name for the Namespace. In my case: „WebNoteModelDatabase“.
Step 2: Add the Code Generation Item
All right. This was standard stuff. We are now going to include the T4 template.
- Open the created EDMX file, right click the background, and from the context menu select Add Code Generation Item and chose the item “ADO.NET Unit Testable Repository Generator”. You could use the name “WebNoteModel.tt” here. (Note: the screenshot is outdated, I renamed the extension. The previous name was: „ADO.NET Mocking Context Generator – Extended“)
- The T4 templates have generated some new files. This includes all the required POCOs (Plain Old CLR Object), a simple ObjectContext and an Interface that should be used to access it. If you get compilation errors, then you should reference the following assemblies:
- Microsoft.Practices.Unity (download at http://unity.codeplex.com)
- Microsoft.VisualStudio.QualityTools.UnitTestFramework (included with Visual Studio)
Step 3: Use the Repository
To start coding you just have to create a partial class with the name of the entity container and the suffix “Repository”. (eg. “public partial class WebNoteRepository”). The following sample shows all CRUD (Create, Read, Update and Delete) operations on the Entity “Note”.
namespace WebNoteMvc.Models { using System; using System.Collections.Generic; using System.Linq; /// <summary> /// Sample Repository /// </summary> public partial class WebNoteRepository { /// <summary> /// Gets all notes from DB /// </summary> /// <returns>all notes from DB</returns> public IEnumerable<Note> GetAllNotes() { return this.Context.Notes.ToList(); } /// <summary> /// Gets one note from DB /// </summary> /// <param name="id">The id of the note to show.</param> /// <returns>notes from DB</returns> public Note GetNote(int id) { Note noteToShow = (from n in this.Context.Notes where n.NoteId == id select n).FirstOrDefault(); return noteToShow; } /// <summary> /// Adds the a new note to DB. /// </summary> /// <param name="noteToAdd">The note to add.</param> public void AddNote(Note noteToAdd) { noteToAdd.Added = DateTime.Now; this.Context.Notes.AddObject(noteToAdd); this.Context.SaveChanges(); } /// <summary> /// Edits one note note. /// </summary> /// <param name="noteData">note data.</param> public void EditNote(Note noteData) { Note noteToEdit = this.GetNote(noteData.NoteId); if (noteToEdit == null) { return; } noteToEdit.Title = noteData.Title; noteToEdit.Message = noteData.Message; this.Context.SaveChanges(); } /// <summary> /// Deletes one note note. /// </summary> /// <param name="id">The id of the note to delete.</param> public void DeleteNote(int id) { Note noteToDelete = this.GetNote(id); if (noteToDelete == null) { return; } this.Context.Notes.DeleteObject(noteToDelete); this.Context.SaveChanges(); } } }
Step 4: Use the unit test
The following example shows a simple unit test. The T4 template has generated a base class for you. You just have to inherit from the XBaseRepository-class. The class requires you to implement the abstract methods that should return a list of Entities. These Entities “simulate” a real database.
namespace WebNoteMvc.Tests.Models { using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using NUnit.Framework; using WebNoteMvc.Models; using WebNoteMvc.Models.WebNoteUnitTest; using Assert = NUnit.Framework.Assert; using IgnoreAttribute = Microsoft.VisualStudio.TestTools.UnitTesting.IgnoreAttribute; /// <summary> /// Example test for the WebNoteRepository /// </summary> [TestClass] public class WebNoteRepositoryTest : WebNoteBaseRepositoryTest { [TestMethod] public void GetAllNotesTest() { // Arrange IEnumerable<Note> expected = this.CreateNotesList(); // Act IEnumerable<Note> actual = Repository.GetAllNotes(); // Assert Assert.That(actual, Is.EquivalentTo(expected)); } [TestMethod] public void AddNoteTest() { // Arrange int countBefore = this.Context.Notes.Count(); // Act Repository.AddNote(new Note()); int countAfter = this.Context.Notes.Count(); // Assert Assert.That(countBefore + 1, Is.EqualTo(countAfter)); Assert.That(this.Context.SavesChanged); } [TestMethod] public void EditNoteTest() { // Arrange Note noteToChange = new Note { NoteId = 2, Title = "Micky", Message = "Maus" }; // Act Repository.EditNote(noteToChange); Note changedNote = (from n in this.Context.Notes where n.NoteId == noteToChange.NoteId select n).First(); // Assert Assert.That(changedNote.Title, Is.EquivalentTo(noteToChange.Title)); Assert.That(changedNote.Message, Is.EquivalentTo(noteToChange.Message)); Assert.That(this.Context.SavesChanged); } [TestMethod] public void DeleteNoteShouldThrowExceptionTest() { // Arrange const int UnknownId = 9999; // Act TestDelegate deleteAction = () => Repository.DeleteNote(UnknownId); // Assert Assert.DoesNotThrow(deleteAction); } [TestMethod] [Ignore] public void GetNoteShouldThrowExceptionTest() { // Arrange const int UnknownId = 9999; // Act TestDelegate getAction = () => Repository.GetNote(UnknownId); // Assert Assert.Throws<InvalidOperationException>(getAction); } [TestMethod] public void GetNoteShouldNotCallSaveChangesTest() { // Arrange var expected = new Note { NoteId = 3, Title = "Unit", Message = "Test", Added = DateTime.Parse("2010-10-29", CultureInfo.InvariantCulture) }; // Act var actual = Repository.GetNote(expected.NoteId); // Assert Assert.That(actual, Is.EqualTo(expected)); Assert.That(!this.Context.SavesChanged); } /// <summary> /// Returns a collection for the MockObjectSet /// </summary> /// <returns>three Notes</returns> public override List<Note> CreateNotesList() { DateTime friday = DateTime.Parse("2010-10-29", CultureInfo.InvariantCulture); return new List<Note> { new Note { NoteId = 1, Title = "Hello", Message = "World", Added = friday }, new Note { NoteId = 2, Title = "Foo", Message = "Bar", Added = friday }, new Note { NoteId = 3, Title = "Unit", Message = "Test", Added = friday } }; } } }
Step 5: Download the sample solution
All shown files can reviewed in a demo solution!
Download the extension here:
ADO.NET Unit Testable Repository Generator