John
John

Reputation: 3402

In TDD and DDD, how do you handle read-only properties in fakes?

Question

How do you handle read-only fields when creating fakes?

Background

I'm in the beginner stages of using ASP.Net MVC and am using Steven Sanderson's Sports Store and Scott Gu's Nerd Dinner as examples. One small problem that I've just hit is how to work with read-only properties when doing fakes. I'm using LINQToSQL.

My interface is:

public interface IPersonRespository
{   
    Person GetPerson(int id);
}

and my fake becomes

public class FakePersonRepository
{
    public Person GetPerson(int id)
    {
        return new Person {id="EMP12345", name="John Doe", age=47, ssn=123-45-6789, totalDrWhoEpisodesWatched=42};
    }
}

Here's my problem. The fields id, ssn and totalDrWhoEpisodesWatched are read-only, so the above code won't actually work. However, I don't recognize how to create a fake new person and set a read-only property. I'm sure there is a solution, but I haven't come across it yet in my searches.

Update: Inheritance + Property Hiding as a Potential Solution?

I haven't yet decided upon a firm solution to the problem. I dislike the notion of modifying my Domain classes for the purposes of creating fakes. To me, adding markup to the domain classes in order to do testing is a form of added coupling -- coupling to the implementation of your test. I'm now investigating another possibility, which is to create a FakePerson class, which inherits from Person, but hides the properties with new read-write properties.

public class FakePerson: Person
{
    public new int age { get; set; }
    public new string ssn { get; set; }
    public new int totalDrWhoEpisodesWatched { get; set; }
}

So far, this solution is how I am leaning. It does break the Liskov Substitution Principle, however that doesn't bug me as much in a test project. I'd be glad to hear any criticism and/or feedback on this as a solution.

Winner: Mock Frameworks

Moq appears to do the job. My last solution of hiding the property through inheritance does, in fact, work, however by using Moq, I get a standardized set of functionality that is more maintainable. I assume that other mock frameworks have this functionality, but I haven't checked. Moq is said to be more straightforward for the beginning mock writing, which I definitely am right now.

Upvotes: 5

Views: 1718

Answers (5)

Jim Counts
Jim Counts

Reputation: 12795

I also use Moq. I love it and it works great. But, before I started using Moq, I wrote many fakes. Here's how I would have solved the problem using fakes.

Since a fake can have additional methods that the "production" implementation doesn't have, I would add a few extra methods to my fake implementation to handle setting the read-only portion.

Like this:

public class FakePersonRepository : IPersonRespository
{
    private IDictionary<int, Person> _people = new Dictionary<int, Person>();

    public Person GetPerson(int id)  // Interface Implementation
    {
        return _people(id);
    }

    public void SetPerson(int id, Person person)  // Not part of interface
    {
         _people.Add(id, person);
    }

}

Upvotes: 0

mvr
mvr

Reputation: 161

Consider mocking the Person type in your test. Example using Moq:

var mock = new Mock<Person>();
mock.SetupGet(p => p.id).Returns("EMP12345");
mock.SetupGet(p => p.ssn).Returns("123-45-6789");
mock.SetupGet(p => p.totalDrWhoEpisodesWatched).Returns(42);
return mock.Object;

Otherwise, try finding out how LINQ to SQL sets those read only properties.

EDIT: If you attempt the above and Moq throws an ArgumentException in the SetupGet call with the message "Invalid setup on a non-overridable member: p => p.id", then you need to mark the property as virtual. This will need to be done for each property whose getter you wish to override.

In LINQ to SQL, this can be done in the OR designer by selecting the property, then in the Properties window set Inheritance Modifier to virtual.

Upvotes: 6

Arnis Lapsa
Arnis Lapsa

Reputation: 47567

If it's for tests - consider using reflection. That wouldn't involve messing around your domain model.

For example - i got FactoryBase class, which uses reflection to set needed prop by lambda expression through parameters (like this). Works like a charm - creating new factory is simple as defining repository type and default entity data.

Upvotes: 0

dss539
dss539

Reputation: 6950

In .NET, you could mark your setters as "internal" and use the InternalsVisibleTo assembly attribute to make internals visible to your test assembly. That way your setters won't be public, but you can still access them.

note: even though the question isn't tagged .NET, I assumed it was based on your usage of object initializer syntax. If my assumption was wrong, this suggestion does not apply (unless the language you're using has an equivalent feature, of course).

Upvotes: 1

Joel Martinez
Joel Martinez

Reputation: 47749

You can only set readonly properties in the constructor of the class. The Person object should have a constructor that accepts id, ssn, and totalDrWhoEpisodesWatched. Of course, if this is a linqtosql generated object, you might have issues modifying that as the code is auto-generated.

You could consider using a mapped object to expose in your repository ... so you'd never actually have to use your linqtosql object as your model.

Upvotes: 1

Related Questions