Demystifying The Code

I’m Baaaaaack

Pig

My blogging has moved to www.deveducate.com/blog

You may be wondering where I have been lately and why I haven’t been posting.  Well,  I have great news.  I’m back blogging, but at a new location: www.deveducate.com/blog.   You can subscribe to the rss feed here

Over the past 10 months, I’ve been busy creating deveducate.com, as well as developing our first training session: “Understanding Entity Framework 4”.  I also did a West Coast (USA) tour, speaking on the Entity Framework at Microsoft offices in 5 cities. 

What is DevEducate.com?

DevEducate.com is my baby – so don’t call it ugly.  BTW, did you ever notice that everyone thinks that their baby is cute – and yet there are ugly babies…  Just sayin’. 

Seriously, I have a huge passion for teaching people how to exploit technology in their applications.  DevEducate.com is the company I founded to do just that.  We are an online training company whose goal is to simplify learning complex technologies.

Visual Studio 2010 and .NET 4 Beta 2 – Available Today

Today is a big day for developers.  We released Visual Studio 2010 and .NET 4 Beta 2 to MSDN Subscribers (it will be available generally on Microsoft.com later in the week). 

image

Please visit the Visual Studio 2010 Beta 2 landing page here to download.

image

Happy coding…

Patterns-Based Silverlight Development Blog / Screencast Series Index

I am in the midst of putting together a blog / screencast series illustrating developing Silverlight 3 application, taking advantage of various design patterns.  Some of the patterns we will cover are the Repository, the Pipeline, the Service Agent and Model View ViewModel.  I will be building a Sample HelpDesk Application along the way (see below).

I will keep this post updated with the links to all of the blog posts and screencasts:

Blog Posts

Screencasts

 

 

Screenshot

The following is a screenshot of the sample application we will be creating throughout this series.

image

Patterns-Based Silverlight Development – Part III – Pipeline Pattern

Introduction

In yesterday’s post, I build our Repository interface and the implementation, as well as added some server-side validation, following a simple pattern.  I also added a test project and wrote some tests to test the our validation logic.  In this post I will implement the Pipeline pattern.  I will then implement a fake repository and use it to test our Pipeline.

 

Acknowledgements

Most of what you will see in this post follows very closely with what Rob Connery outlined in his MVC Storefront series.  I am, however, not using TDD, as that is not the goal of this series.  Again, I would highly recommend following his series if you haven’t already.

 

The Pipeline Pattern

“In software engineering, a pipeline consists of a chain of processing elements …, arranged so that the output of each element is the input of the next.” – Wikipedia – Pipeline (software)

Whether we know it or not, we have all used pipelines.  Perhaps the best examples are WCF or IIS.  The description above from Wikipedia (the purveyor of all knowledge) hit the most salient points on the head.  You have a chain of processing elements.  Each element takes an input and has an output.  The output of one element is the input of another.  In a typical pipeline, each element is designed to take in an input of a specific type, perform some operation on it, and return the same type as the output.

 

IQueryable<T> Overview

The following comes straight from the online documentation for IQueryable<T> and are quite illuminating. 

image

The Expression property returns the expression tree that is associated with the IQueryable instance.  When you do things like add a ‘where’ or a ‘select’ or ‘order by’ (the list goes on …) to your query, it is stored in the expression tree.  This in-memory representation of your query is the key enabler for allowing deferred execution.  What this means is that we can continually add to the query (the expression tree) up until the time we execute it.  The query is not executed until we enumerate over the results. 

Let’s take a look at a simple example that will help illustrate this.  Looking back to our repository, we implemented only one fetch operation for tickets.  It looks like this:

public IQueryable<Ticket> GetTickets()
{
    return db.Tickets;
}

You might have expected multiple fetch operations like GetTicketsBySeverityLevel or GetTicketsByPage.  This is how we typically built this layer in the past.  The challenge with this approach is that any time you wanted to return a different slice of data, you had to go back and add another operation to the Repository.  With IQueryable<T>, we can simply call GetTickets and add to the query to suit our needs.  So instead of implementing a GetTicketsBySeverityLevel in the Repository, we could do the following:

//Get the IQueryable<T> from the repository 
TicketRepository rep = new TicketRepository();
IQueryable<Ticket> query = rep.GetTickets();

//Add a where clause (by severity level)
query = query.Where(t => t.SeverityLevelID == 1);

//Fetch the data
List<Ticket> tickets = query.ToList();

We are going to take advantage of this in implementing our Pipeline.  The other enabling technology we are going to be taking advantage of is extension methods.  I’ll cover that now…

 

Extension Methods Overview

Extension methods let you extend an existing type without actually deriving from it.  At first glance, this raises some red flags surrounding security, but an extension method only has access to the public members of the type it is extending.  This is no different than any other code that may operate on this type.  So what is an extension method really?  It is a pre-compile syntax that, among other things, enables LINQ and allows you to create more readable and maintainable code.  Let’s take a look at an example to illustrate the readability/maintainability part.  Let’s assume that I want to expose the functionality that will translate English to Jive.  Obviously, this will operate on a string.  The old-timey way to do this would to be to write a static method and consume it  like so:

//Traditional Static Method
public static string TranslateToJive(string text)
{
    return translateToJive(text);
}
//Call our traditional static
string greeting = "Relax";
Console.WriteLine(StringExtensions.TranslateToJive(greeting));

We can easily implement this functionality as an Extension Method.  Extension Methods are public static (they have to be both public and static) methods in a static class.  What transforms a static method into an extension method is prepending the ‘this’ keyword to the first method parameter.  Whatever the type of that parameter is the type we will be extending.  For example, we could re-write our earlier example like this:

//Extension method, extending string
public static string ToJive(this string text)
{
    return translateToJive(text);
}
//Call our extension method
string greeting = "Relax";
Console.WriteLine(greeting.ToJive());

While both bits of code will output the same thing to the console: “Jes hang loose”, as you can see, the code with the extension method is simpler to read.  In this simple example, you may not see a great increase in readability, but you will see it more clearly when we get into our pipeline example.  Another great benefit of the extension method is that it provides intellisense support.  We do not need to know about the existence of a TranslateToJive method that takes a string.  We simply press ‘.’ after our string and we see:

image

 

Building our Pipeline

Now let’s tie all of the concepts brought out in this post together by implementing our pipeline.  Our pipeline will be a bunch of extension methods that extend IQueryable<Ticket>.  These extension methods will take in an IQueryable<Ticket> (or in this case extend it, logically the same thing) and return IQueryable<Ticket>.  As we will see, we will be able to string a bunch of these extension methods together.

There will be some extension methods that don’t return IQueryable<Ticket>, perhaps just returning a single ticket.  An example would be a “ByTicketId” extension method.  Methods that do not return IQueryable<T> will end that pipeline. 

Another name for the Pipeline pattern is ‘Pipes and Filters’.  That name explains exactly what we want to do.  We want to create a group of filters that can be applied to Tickets.  Let’s create our Ticket filters.

  1. Create a TicketFilters static class in HelpDesk.Data
    • Right-Click HelpDesk.Data –> Add –> Class
    • Name it TicketFilters.cs (I put mine in a Filters folder)
    • Mark the class public and static
  2. Add the following extension methods
public static class TicketFilters
{
    public static IQueryable<Ticket> BySeverityLevelID(
        this IQueryable<Ticket> query,
        int id)
    {
        return query.Where(q => q.SeverityLevelID == id);
    }

    public static IQueryable<Ticket> ByPage(
        this IQueryable<Ticket> query,
        int pageNumber,
        int pageSize)
    {
        int skip = (pageNumber) * pageSize;

        return query.Skip(skip).Take(pageSize);
    }

    public static Ticket ByTicketID(this IQueryable<Ticket> query,
        int id)
    {
        return query.SingleOrDefault(q => q.TicketID == id);
    }
}

 

Does the Pipeline Increase Readability?

Consider this scenario.  You want to get the second page of 10 Tickets with a SeverityLevel of 1.  Here is how you would do this without our extension methods:

var tickets = repository.GetTickets()
    .Where(t => t.SeverityLevelID == 1)
    .Skip(10)
    .Take(10);

versus this with our extension methods:

var tickets = rep.GetTickets().BySeverityLevelID(1).ByPage(2, 10);

Quite a difference (in my opinion).

 

Testing our Pipeline

When I wrote the tests against my validation logic, I was able to simply cruft up a Ticket object and set whatever properties I needed to set (or not set).  Here, however, I will need to call into my Repository.  But do I really want to do that?  Take the ByTicketID filter.  It takes in an integer like 1.  If we wrote our test calling this filter with a 1 and it failed it may be because there was no record in the database with an ID of 1.  This may lead to a false negative.  Our code actually worked as designed, the test failed because of what was in the database (or rather wasn’t). 

Couldn’t we write some test precondition that checks to see if there is a record with ID = 1 in the database, if not, insert it?  Yes, we could.  But then, to be good citizens, we would probably want to add some code to remove the newly inserted record.  We really don’t want to be in the business of managing our test database.  We want to test our logic.

For this reason, what we might want to do is to use a fake or mock repository.  Rhino Mocks is a popular framework that provides this functionality (and there are many other great tools).  However, for the purpose of this post, I am going to simply implement my own fake repository.  In future posts, I may replace that with Rhino Mocks or another solution.

Add The Fake Ticket Repository

  1. Right-click the HelpDesk.Server.Tests project –> Add –> New Folder –> Name it Fakes
  2. Right-click the Fakes folder –> Add –> Class
  3. Name it FakeTicketRepository.cs
  4. Mark it public
  5. Add the following code:
public class FakeTicketRepository : ITicketRepository
{
    private List<Ticket> ticketList;
    private List<SeverityLevel> severityLevelList;

    public FakeTicketRepository(List<Ticket> tickets,
        List<SeverityLevel> severityLevels)
    {
        ticketList = tickets;
        severityLevelList = severityLevels;
    }

    public IQueryable<Ticket> GetTickets()
    {
        return ticketList.AsQueryable();
    }

    public IQueryable<SeverityLevel> GetSeverityLevels()
    {
        return severityLevelList.AsQueryable();
    }

    public void Add(Ticket ticket)
    {
        ticketList.Add(ticket);
    }

    public void Delete(Ticket ticket)
    {
        ticketList.Remove(ticket);
    }

    public void Save()
    {
        foreach (Ticket ticket in ticketList)
        {
            if (!ticket.IsValid)
                throw new ValidationException("Rule violations");
        }

        return;
    }

    #region Helper Static Methods
    public static FakeTicketRepository CreateFakeTicketRepository()
    {
        var repository = new FakeTicketRepository(CreateTestTickets(), CreateTestSeverityLevels());
        return repository;
    }

    public static List<SeverityLevel> CreateTestSeverityLevels()
    {
        List<SeverityLevel> slevels = new List<SeverityLevel>();

        slevels.Add(new SeverityLevel() { SeverityLevelID = 1, Level = "High" });
        slevels.Add(new SeverityLevel() { SeverityLevelID = 2, Level = "Medium" });
        slevels.Add(new SeverityLevel() { SeverityLevelID = 3, Level = "Low" });

        return slevels;
    }

    public static List<Ticket> CreateTestTickets()
    {
        List<Ticket> tickets = new List<Ticket>();
        for (int i = 0; i < 10; i++)
        {
            Ticket sampleTicket = new Ticket()
            {
                TicketID = i,
                ShortDescription = "Short Description " + i.ToString(),
                LongDescription = "Long Description " + i.ToString(),
                TicketDate = DateTime.Now.AddDays(i * -1),
                IsOpen = (i % 2 == 0),
                SeverityLevelID = 1,
                SeverityLevel = CreateTestSeverityLevels()[0]
            };

            tickets.Add(sampleTicket);
        }
        return tickets;
    }
    #endregion
}

What you should gather from this code is the following:

  • I am using generic Lists (List<T>) to store my fake ticket and severity level data
  • I overloaded the constructor, forcing you to pass in the fake Ticket and SeverityLevel lists
  • I implemented IRepository.  All of the IRepository implementations operate on the local Lists
  • I created a helper static method CreateFakeTicketRepository that will return a FakeTicketRepository with fake data in it.  If you don’t feel like creating your own fake data and passing it in, you can use this out-of-the-box fake data.

Some Pipeline Tests

[TestMethod]
public void Passing_ByTicketID_Filter_1_Returns_The_Appropriate_Ticket()
{
    ITicketRepository rep =
        Fakes.FakeTicketRepository.CreateFakeTicketRepository();

    Ticket ticket = rep.GetTickets()
                    .ByTicketID(1);

    Assert.IsTrue(ticket.TicketID == 1);
}

[TestMethod]
public void Passing_ByPage_Filter_Page_1_PageSize_3_Should_Return_Tickets_With_IDS_3_4_5()
{
    ITicketRepository rep =
        Fakes.FakeTicketRepository.CreateFakeTicketRepository();

    var tickets = rep.GetTickets().ByPage(1, 3).ToList();

    Assert.IsTrue(tickets[0].TicketID == 3 &&
        tickets[1].TicketID == 4 &&
        tickets[2].TicketID == 5);

}

You can see from the above code that I am using my fake ticket repository.  I am then testing some of my filters.  Because I know what the test data looks like, I am assured that I am testing my filter logic and not my data.

 

Sample Code

You can get the sample code for implementing the pipeline here.  (You will need to be a registered user of the site to get the code)

What’s Next

In the next post, I will implement the WCF Service layer. 

Patterns-Based Silverlight Development – Part II – Repository and Validation

Introduction

In this post I will provide a brief overview of the Repository pattern, implement a Repository in our sample application, establish our server-side validation and add our test project. 

 

Acknowledgements

Most of what you will see in this post follows very closely with the code ScottGu implemented in his NerdDinner tutorial.  In fact, I would highly recommend reading that if you haven’t already.  I will implement the repository, fake repository and validation using the implementations he laid out in that chapter.  I am a big fan of ScottGu’s samples.  I feel they are very effective in walking that delicate balance between simple to understand and useful.

I will deviate a bit from the Gu’s repository in order to implement the Pipeline pattern in the next post.  Further, I will likely dedicate a post in this series to implementing Rhino Mocks for our MockRepository. 

 

The Repository Pattern

“A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection.” – by Edward Hieatt and Rob Mee, http://martinfowler.com/eaaCatalog/repository.html

The major benefits of implementing the Repository pattern are twofold.  First, it abstracts away the data persistence implementation.  This gives you the ability to swap back ends out seamlessly.  This can be especially advantageous today.  You may well choose to swap out your back end database for a cloud-based data source.  Second, and in my opinion more often relevant, is that it facilitates unit testing by providing a layer where you can inject a fake or mock back end.  This allows you to test your code without having a dependence on a database.  This will be very clear in the next post.

 

Implementing the Repository

Add the ITicketRepository Interface

We will use an interface to define the signature of our repository, so the first thing we need to do is to add the ITicketRepository class.  Then we need to add all of the method signatures.  Here it is:

    public interface ITicketRepository
    {
        IQueryable<Ticket> GetTickets();
        IQueryable<SeverityLevel> GetSeverityLevels();

        void Add(Ticket ticket);
        void Delete(Ticket ticket);

        void Save();
    }

Add the TicketRepository implementation

    public class TicketRepository
    {
        HelpDeskDataContext db = new HelpDeskDataContext();

        public IQueryable<Ticket> GetTickets()
        {
            return db.Tickets;
        }

        public IQueryable<SeverityLevel> GetSeverityLevels()
        {
            return db.SeverityLevels;
        }

        public void Add(Ticket ticket)
        {
            db.Tickets.InsertOnSubmit(ticket);
        }

        public void Delete(Ticket ticket)
        {
            db.Tickets.DeleteOnSubmit(ticket);
        }

        public void Save()
        {
            db.SubmitChanges();
        }
    }

There are a few things to notice here.  The first thing is that we are delegating all of the work to the LINQ to SQL framework.  That is why you don’t see much data access code here.  Had I chosen to use the Entity Framework, we would have implemented it here, as well. 

The second, and related, is that we are returning an IQueryable<T> from our fetch operations.  When you compose a query with IQueryable, the clauses you add (where, select, order by, etc) are stored in an expression tree in memory.  What is cool about this is you can continue to add expressions into the tree up until the time you fetch the data.  For example, if a method calls GetTickets(), they will get an IQueryable<Ticket>.  They could then add additional clauses into that query.  For instance, they could add where clause that limits the tickets to those with a high severity level.  We will take full advantage of this when we implement the Pipeline pattern in the next post.  Why did I mention it here and not wait until I talked about the Pipeline pattern?  I did so because, you might notice that for Tickets, there is only 1 fetch: GetTickets().  We don’t have a GetTicketsPage(int pageNum, int pageSize)  that returns pages of tickets or a GetTicketsBySeverityLevel(SeverityLevel level).  This is by design.  We will implement that functionality in the Pipeline.  As far as the Repository is concerned, all we need to do is return the IQueryable<T>.

 

Partial Classes and Partial Methods Described

Partial Classes

You may have noticed that the Ticket and the SeverityLevel class that the L2S (LINQ to SQL) designer created were marked as partial classes:

public partial class SeverityLevel : …
public partial class Ticket : …

Partial classes allow you to split the definition of a class into multiple files.  At compile time, all of the files are compiled together.  As far as the compiler is concerned, they may as well have existed in one file.  This is a big help when working with designer-generated files.  If you were to write some custom logic (say validation logic – hint, hint) directly in the generated file, what would happen when you made a change in the designer and the code was re-generated?  Your hard work would be overwritten.  However, if you were to add your code in another file in a partial class, it would remain.  Nice.

Partial Methods

Partial Classes (or partial Structs for that matter) can contain partial methods.  With a partial method, one Partial Class or Struct contains the signature of the method:

//Definition
partial void OnValidate(System.Data.Linq.ChangeAction action);

The same partial Class (Struct) or more commonly another can contain the implementation:

partial void OnValidate(ChangeAction action)
{
    if (!IsValid)
        throw new ValidationException("Rule violations prevent saving");
}

This again is very useful in designer-generated code.  It is a great point of extensibility.  A very cool thing about partial methods is that if there is no implementation, the method and any calls to it are pulled out at compile time.  However, if there is an implementation, the call to that method will occur.

 

Server Side Validation

Create a Partial Class

As you might imagine, we are going to implement the server-side validation logic for our Ticket in a partial class.  All you need to do is:

  1. Create a class:  Right-click the HelpDesk.Data project –> Add –> Class 
  2. Name it Ticket.cs

  3. Mark it public partial

Implement our Validation

As I stated in the opening summary, I am going to use the simple validation implementation that ScottGu laid out in his NerdDinner tutorial (page 37).  I will provide a bit of an overview here, but for a more thorough discussion see Scott’s tutorial.  To start with, take a look at this code:

RuleViolation.cs

public class RuleViolation
{
    public string ErrorMessage { get; private set; }
    public string PropertyName { get; private set; }
    public RuleViolation(string errorMessage)
    {
        ErrorMessage = errorMessage;
    }
    public RuleViolation(string errorMessage, string propertyName)
    {
        ErrorMessage = errorMessage;
        PropertyName = propertyName;
    }
}

RuleViolation is a simple class with 2 primitives that allow you to indicate the ErrorMessage and optionally the name of the Property that caused the violation.

Ticket.cs

 



public partial class Ticket
{
    public const string ShortDescriptionRequired = "Short Description is required";
    public const string LongDescriptionRequired = "Long Description is required";
    public const string ShortDescriptionTooLong = "Short Description cannot exceed 50 characters";
    public const string LongDescriptionTooLong = "Long Description cannot exceed 500 characters";
    public const string TicketDateRequired = "Ticket Date is required";
    public const string TicketDateCannotExceedCurrentDate =
        "Ticket Date cannot be greater than the current date";

    public bool IsValid
    {
        get { return (GetRuleViolations().Count() == 0); }
    }

    public IEnumerable<RuleViolation> GetRuleViolations()
    {
        if (String.IsNullOrEmpty(ShortDescription))
            yield return new RuleViolation(ShortDescriptionRequired, "ShortDescription");
        if (!String.IsNullOrEmpty(ShortDescription) && ShortDescription.Trim().Length > 50)
            yield return new RuleViolation(ShortDescriptionTooLong, "ShortDescription");
        if (String.IsNullOrEmpty(LongDescription))
            yield return new RuleViolation(LongDescriptionRequired, "LongDescription");
        if (!String.IsNullOrEmpty(LongDescription) && LongDescription.Trim().Length > 500)
            yield return new RuleViolation(LongDescriptionTooLong, "LongDescription");
        if (this.TicketDate == null)
            yield return new RuleViolation(TicketDateRequired, "TicketDate");
        if (this.TicketDate > DateTime.Now)
            yield return new RuleViolation(TicketDateCannotExceedCurrentDate, "TicketDate");
        yield break;
    }

    partial void OnValidate(ChangeAction action)
    {
        if (!IsValid)
            throw new ValidationException("Rule violations prevent saving");
    }
}

 

(For ease of reading, I used constants for the error message text instead of the preferred method of using resource files.)

Take a look at the GetRuleViolations method.  This method can be called and it will return a collection of each and every RuleViolation (thanks to the yield return implementation).  Each condition (if statement) will be evaluated in order.  For each one, In the event the condition is true, the new RuleViolation will be provided to the enumerator (the method returns IEnumerable<RuleViolation>). 

Inside of the method, I have added some sample validation checks.  Clearly, this is not a complete list.  Again, the goal of this series is not to build the complete application, rather, illustrate how to apply certain patterns.  You can clearly see that you could write whatever custom validation you wanted here.  In my examples, I made sure some properties weren’t null, I did some string length checking and made sure a date falls within a range (less than current).  The important thing to realize is that if there are more than one violation, the complete list will be returned.  The other thing to know is that anyone at anytime can call GetRuleViolations without the penalty of an exception being thrown if there are any violations.

The IsValid helper method simply returns true if there are any rule violations.  Again, this can be called without fear of an exception.

The last method is the OnValidate partial method.  As described earlier, the OnValidate signature was defined in the Ticket partial class that the L2S designer generated.  Because we have added the implementation in our Ticket partial class, the method will be called by the LINQ to SQL framework prior to persisting any data.  This gives us a chance to validate the data (thus the name).  We simply call our IsValid method.  If it is not valid (there is at least one RuleViolation), we throw a ValidationException.  This is a slight deviation from what the Gu did in NerdDinner.com.  he threw an ApplicationException.  ValidationException is a simple class that implements Exception (see below).  You will see why I throw a ValidationException when I get to the post on implementing our WCF services.

ValidationException.cs

public class ValidationException : Exception
{
    public ValidationException() { }
    public ValidationException(string message) : base(message) { }
    public ValidationException(string message, Exception inner) : base(message, inner) { }
    protected ValidationException(
      SerializationInfo info,
      StreamingContext context)
        : base(info, context) { }
}

 

Testing our Validation Logic

Well, we have implemented our Repository and our server-side validation logic for Tickets (at least some validation logic).  The next thing I want to do is to add a Test project and add some methods that test our validation logic.  Again, I’m only going to add a couple which should be enough to illustrate the process.

Add a Test Project

  1. Right-Click on the Server Solution Folder –> Add –> New Project
  2. Under Visual C# –> Choose ‘Test’ –> Choose ‘Test Project’
  3. Name it HelpDesk.Server.Tests
  4. Add a reference to HelpDesk.Data
  5. Delete the stubbed out test files:
    • AuthoringTests.txt
    • ManualTest1.mht
    • UnitTest1.cs

Add a Test Class

  1. Right-Click on the HelpDesk.Server.Tests Project –> Add –> New Item
  2. Under Visual C# Items –> Choose ‘Unit Test’
  3. Name it TicketTests
  4. Delete the stubbed out code

Add a couple tests to Test our Validation logic

Now we just need to add the tests to test our logic.  Take a look:

[TestClass]
public class TicketTests
{
    [TestMethod]
    public void Ticket_Should_Be_Invalid_When_ShortDescription_Is_Empty()
    {
        Ticket ticket = new Ticket();
        ticket.TicketID = 1;
        ticket.LongDescription = "Test";
        ticket.IsOpen = false;
        ticket.SeverityLevel = new SeverityLevel() { SeverityLevelID = 1, Level = "High" };
        ticket.SeverityLevelID = 1;
        ticket.TicketDate = DateTime.Now;

        //Make sure ShortDescription is empty
        ticket.ShortDescription = "";

        bool isValid = ticket.IsValid;

        Assert.IsFalse(isValid);
    }

    [TestMethod]
    public void Ticket_Should_Be_Invalid_When_ShortDescription_Is_GreaterThan_50_In_This_Case_60()
    {
        Ticket ticket = new Ticket();
        ticket.TicketID = 1;
        ticket.LongDescription = "Test";
        ticket.IsOpen = false;
        ticket.SeverityLevel = new SeverityLevel() { SeverityLevelID = 1, Level = "High" };
        ticket.SeverityLevelID = 1;
        ticket.TicketDate = DateTime.Now;

        //Set the ShortDescription to 60
        ticket.ShortDescription = "123456789012345678901234567890123456789012345678901234567890";

        bool isValid = ticket.IsValid;

        Assert.IsFalse(isValid);
    }

    [TestMethod]
    public void Ticket_Should_Be_Valid_When_All_Properties_Are_Correct()
    {
        Ticket ticket = new Ticket();
        ticket.TicketID = 1;
        ticket.ShortDescription = "Test";
        ticket.LongDescription = "Test";
        ticket.IsOpen = false;
        ticket.SeverityLevel = new SeverityLevel() { SeverityLevelID = 1, Level = "High" };
        ticket.SeverityLevelID = 1;
        ticket.TicketDate = DateTime.Now;

        bool isValid = ticket.IsValid;

        Assert.IsTrue(isValid);
    }
}

As you can see, my method names are very verbose.  This is by design.  When you have a bunch of tests, it is nice to simply look at the name of a failed test and know what is wrong.  Because we are testing the validation logic, we are able to simply new up a new Ticket and set (or fail to set) the appropriate properties that will define our tests.  We don’t need to go through the Repository (yet). 

Here is what it looks like when I run the tests:

image

image

 

Sample Code

You can get the sample code for Building the Repository and Validation here.  (You will need to be a registered user of the site to get the code)

 

What’s Next

In the next post, I will implement the Filter layer.  At that point I will need to go through my Repository (or my Fake / Mock repository) when testing.

« Previous PageNext Page »

Demystifying The Code