Ok, I’m not a happy owner of Typemock, hence I can’t use it to mock extension methods.
I will show you two really simple workarrounds for achieving this.
I have some simple extension methods that extends IQueryable. One of the extensions is responsible for checking if a certain username allready is taken.
The extension method
public static bool UsernameIsTaken(this IQueryable<UserAccount> userAccounts, string username)
{
return
userAccounts.Where(
u =>
u.Username.Equals(username, StringComparison.InvariantCultureIgnoreCase)).Count() > 0;
}
As I’m using the Moq-framework for setting up my fakes (in this case stub, see earlier post) I will get an exception.
The test as I want it (which doesn’t work) looks like this
[TestMethod]
public void Validate_TakenUsername_GivesViolation()
{
var userAccount = UserAccountFactoryForTests.CreateValidUserAccount();
var userAccountStoreStub = Fake.Stub.New<IQueryable<UserAccount>>();
Fake.Stub.Returns(userAccountStoreStub, stub => stub.UsernameIsTaken(userAccount.Username), true);
var validator = new NewUserAccountValidator(userAccountStoreStub);
var validationResult = validator.Validate(userAccount);
Assert.AreEqual(TimeTracking.Domain.Resources.UserAccountValidationMessages.UsernameIsAllreadyTaken, validationResult.GetViolationsByMembername("Username")[0].ErrorMessage);
}
This stub is fairly simple to replace manually. All I need is a generic List of UserAccount that contains an instance of an useraccount that has the same username as the username I’m validating.
Solution 1 – Setup a generic list and pass it as IQueryable
[TestMethod]
public void Validate_TakenUsername_GivesViolation()
{
var userAccount = UserAccountFactoryForTests.CreateValidUserAccount();
var userAccountStoreStub = new List<UserAccount>
{
UserAccountFactoryForTests.CreateValidUserAccount()
}.AsQueryable();
var validator = new NewUserAccountValidator(userAccountStoreStub);
var validationResult = validator.Validate(userAccount);
Assert.AreEqual(TimeTracking.Domain.Resources.UserAccountValidationMessages.UsernameIsAllreadyTaken, validationResult.GetViolationsByMembername("Username")[0].ErrorMessage);
}
This time I was lucky, since the extension method was on the IQueryable, but what if it was something that is totally custom? Just let the extension method consume something that you can stub. In this case, e.g., a Func (see Daniel Cazzulino’s blog).
Solution 2 – Let the extension method consume something you can stub
public static class UserAccountQueries
{
public static Func<IQueryable<UserAccount>, string, bool> userNameIsTaken = (userAccounts, username) =>
userAccounts.Where(
u =>
u.Username.Equals(username, StringComparison.InvariantCultureIgnoreCase)).Count() > 0;
public static bool UsernameIsTaken(this IQueryable<UserAccount> userAccounts, string username)
{
return userNameIsTaken(userAccounts, username);
}
}
[TestMethod]
public void Validate_TakenUsername_GivesViolation()
{
var userAccount = UserAccountFactoryForTests.CreateValidUserAccount();
UserAccountQueries.userNameIsTaken = (stub, username) => true;
var validator = new NewUserAccountValidator(new List<UserAccount>().AsQueryable());
var validationResult = validator.Validate(userAccount);
Assert.AreEqual(TimeTracking.Domain.Resources.UserAccountValidationMessages.UsernameIsAllreadyTaken, validationResult.GetViolationsByMembername("Username")[0].ErrorMessage);
}
In my scenario I used solution 1, but in the future I will probably refactor away my code from the extension methods.
//Daniel
Like this:
Like Loading...