Question

Hope I can explain this somewhat decently, as it's blowing a fuse in my brain today. I'm learning TDD in C#, so I'm still trying to rewire my brain to fit it.

Let's say I have a User class, that previously had a static method to retrieve a User object (simplified below).

public static User GetUser(string username)
{
   User user = GetUserFromCache(username);
   if(user == null)
   {
       user = GetUserFromDatabase(username);
       StoreObjectInCache(user);
   }
   return user;
}

So I'm trying to rewrite this to use dependency injection so I can fake out the "GetUserFromDatabase" method if it needs to go there. That means I have to make the function not static. Whereas the data access layer would construct the user object from the database, mapping the returned columns to the object properties, a retrieval from cache would return a true-blue User object. However, in a non-static method, I can't just say

this = GetUserFromCache(username);

Because it just doesn't work that way. Though I'm by no means the world expert in how to dance around this with OO, it looks like I'd almost have to grab the User object from cache and write another mapping function that would store the returned User object properties into the new User instance.

What's the solution here? Any OO magic I'm missing? Is the only solution to refactor everything to use factories instead of having the instantiation logic in the object itself? Or have I been staring at this too long and missing something completely obvious?

Was it helpful?

Solution

I don't think you're missing any magic and I think refactoring to remove the persistence code from your business objects and into your persistence layer is the right way to go both from a unit testing and a design perspective. You may want to think about having the cache sit between your business layer and the persistence layer, mediating the retrieval/update of your business objects to simplify things. You should be able to mock/fake your cache and persistence layer if you separate things out this way.

OTHER TIPS

Unit testing code that does date processing based on today's date

Before

  • There is some code that uses the database to fetch a User and place it into the cache.

After

  • There is some code that uses the database to fetch a User
  • There is some code that places the User in the cache.

These two sets of code should not be dependent on each other.

public static Func<string, UserName> Loader {get;set;}

public static Constructor()
{
  Loader = GetFromDataBase;
}

public static User GetUser(string userName)
{
  User user = GetUserFromCache()
  if (user == null)
  {
    user = Loader(userName);
    StoreUserInCache(user);
  }
  return user;
}    

public void Test1()
{
  UserGetter.Loader = Mock.GetUser;
  UserGetter.GetUser("Bob");
}

Classically, an interface would be used instead of a Func. If more than one method is involved, an interface is an obvious choice over the Func. If the methods implementations themselves are static, Func is a way to do abstraction over them.

What I am missing in your example is the context of your call to "GetUser". This is probably because with a static method you don't need to think about as you can call it from everywhere. In DI this means the repository needs to be referenced by the sender in some way, a field most likely.

When your cache is a field of some object, a facade probably, you could use this make your cache a proxy of your database.

So you would have:

class ApplicationFacade{
  private IUserRepository users = null;

  public doStuff(){
    this.users.GetUser("my-name");
  }
}

where IUserRepository is a common interface for your cache, fake database and database. Something simple like:

interface IUserRepository{
  User GetUser(string username);
}

Your cache could now be a simple object implementing this interface and because cache is injected the DI container can also inject into it.

class Cache : IUserRepository {
  private IUserRepository users = null;
  public User GetUser(string username){
    if (this.NotCached(username)){
      this.ToCache(this.users.GetUser(username));
    }
    return this.FromCache(username);
  }
}

Now depending on what you want you can inject your fake, cache or database into your facade object and if you use your cache object you can inject your fake er database into it as desired (or even an other cache if you really wanted to).

Of cause the actual injection mechanism depends on your DI container and may require some extra code as public properties or constructor fields.

Take a look at Refactoring static method / static field for Testing

The approach suggested there may work for you, if for some reason you can't refactor everything to separate concerns as suggested in another answer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top