TDD: Static methods, dependency injection, caching and you!

I hope I can explain this a bit decently, as today it blows up a fuse in my brain. I am learning TDD in C #, so I'm still trying to remake my brain to fit it.

Say I have a User class that previously had a static method for retrieving 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 that I can fake the GetUserFromDatabase method if it should go there. This means that I have to make the function non-static. While the data access layer would create a user object from the database, matching returned columns with object properties, retrieving from the cache would return a real blue User object . However, in the non-stationary method, I can’t just say

this = GetUserFromCache(username);

Because it just doesn't work. Although I am by no means a global expert on how to dance around this with OO, it seems I almost needed to grab the User object from the cache and write another mapping function that would save the returned properties of the user object in a new User instance.

? OO, ? , , ? - ?

+5
4

, - , , - - , . , , - , / - . / , .

+7

,

  • , .

  • ,
  • , .

.

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");
}

Func . , Func. , Func - .

+4

, , - "GetUser". , , , . DI , - , , .

- , , , , - .

, :

class ApplicationFacade{
  private IUserRepository users = null;

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

IUserRepository - , . - :

interface IUserRepository{
  User GetUser(string username);
}

, , , DI .

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);
  }
}

, , , , , , ( , ).

Due to the fact that the actual injection mechanism depends on your DI container, some additional code may be required as public properties or constructor fields.

+1
source

See Refactoring a static method / static field for testing.

The proposed approach may work for you if for some reason you cannot reorganize everything to separate the problems, as suggested in another answer.

0
source

All Articles