In the last post Unit testing with Machine.Specifications (aka MSpecs) and FakeItEasy, I have covered basic unit testing with MSpecs and FakeItEasy. Today first I am going to go through some more tests. And then I will cover the concepts of white-box testing with MSpecs and FakeItEasy.
New tests for positive cases
In the last post, I just covered only the exception test case. Today in this post, I will first start with a positive test case. I will test the scenario where a proper User
object is returned.
To achieve that, first of all, I will create a new class to represent the test case.
[Subject(typeof(UserManager))]
public class When_User_Returned
{
}
Next, I will add the code to establish the context and write the assertions.
[Subject(typeof(UserManager))]
public class When_User_Returned
{
static UserManager Subject;
static User userResponse;
Establish context = () => {
var userProvider = A.Fake();
A.CallTo(() => userProvider.Get(A._)).Returns(new User { Name = "Test" });
Subject = new UserManager(userProvider);
};
Because of = () => userResponse = Subject.Get(1);
It should_give_non_null_user = () => userResponse.ShouldNotBeNull();
It should_have_user_Name_as_Test = () => userResponse.Name.ShouldBeEqualIgnoringCase("Test");
}
Here one thing in particularly notable. The code where I am setting up IUserProvider
to return a User
object. In this section of the code, I am using A._
as a parameter to the Get
method. What this tells us that as long as any Integer
parameter is passed as an argument, return a User
object with Name = "Test"
.
Adding a ILogger interface
To support the logging facility, I will add a ILogger
interface to the project. This interface will have just one method for logging.
public interface ILogger
{
void Log(string message);
}
Next, I will pass this interface to the UserManager
constructor and use it in the Get
method for logging.
public class UserManager : IUserManager
{
private readonly IUserProvider userProvider;
private readonly ILogger logger;
public UserManager(IUserProvider userProvider, ILogger logger)
{
this.userProvider = userProvider;
this.logger = logger;
}
public User Get(int userId)
{
if(userId <= 0)
{
var message = $"User id has to be a positive integer. Value passed {userId}";
logger.Log(message);
throw new ArgumentException(message);
}
return userProvider.Get(userId);
}
}
White-box testing
The focus of the white-box testing here would be to see if the ILogger
is getting called with a specific argument, when a negative user id is passed.
First of all, I will update the negative test which I wrote in the previous post, to incorporate the ILogger
change.
[Subject(typeof(UserManager))]
public class When_User_Id_Passed_As_Negative_Value
{
static UserManager Subject;
static Exception Exception;
static ILogger logger;
Establish context = () => {
var userProvider = A.Fake();
logger = A.Fake();
Subject = new UserManager(userProvider, logger);
};
Because of = () => Exception = Catch.Exception(() => Subject.Get(-1));
It should_fail = () => Exception.ShouldBeOfExactType();
}
Finally, I will update the code to add code for white-box test and ensure that the ILogger
is getting called.
[Subject(typeof(UserManager))]
public class When_User_Id_Passed_As_Negative_Value
{
static UserManager Subject;
static Exception Exception;
static ILogger logger;
Establish context = () => {
var userProvider = A.Fake();
logger = A.Fake();
Subject = new UserManager(userProvider, logger);
};
Because of = () => Exception = Catch.Exception(() => Subject.Get(-1));
It should_fail = () => Exception.ShouldBeOfExactType();
It should_log_message = () => A.CallTo(() => logger.Log(A._)).MustHaveHappenedOnceExactly();
}
Conclusion
As we can see, apart from standard test cases, doing white-box testing is also a breeze using MSpecs and FakeItEasy.
The output of the tests: