Introduction

We always get confused with the meaning of Mock, Stub, Fake and Spy. I have tried to explain the meaning of these terms and differences between them in some simple ways for beginners.
All of these concepts are mainly used to replace the code dependencies with some alternatives so, that we can concentrate on the unit we are testing while writing in-memory tests.

Stub

Below is the stubbed version of an active directory user store where GetUserRole() and GetAllUsers() functions always return the same output regardless of the input.
  1. public class StubUserStore : IUserStore
  2. {
  3. public string GetUserRole(string username)
  4. {
  5. return "contributor";
  6. }
  7. public List<UserDetail> GetAllUsers()
  8. {
  9. return new List<UserDetail>()
  10. {
  11. new UserDetail{ Role = "administrator", Name = "admin"},
  12. new UserDetail(){ Role = "contributor", Name = "User 1"}
  13. };
  14. }
  15. }
  16. public interface IUserStore
  17. {
  18. string GetUserRole(string username);
  19. }
  20. public class UserDetail
  21. {
  22. public string Name { get; set; }
  23. public string Role { get; set; }
  24. }

Fake

Below is the fake version of the same user store where the behavior of the GetUserStore() function can change based on input.
  1. public class FakeUserStore : IUserStore
  2. {
  3. public string GetUserRole(string username)
  4. {
  5. if (username == "admin")
  6. return "administrator";
  7. else
  8. return "contributor";
  9. }
  10. }
  11. public interface IUserStore
  12. {
  13. string GetUserRole(string username);
  14. }

Spy

As shown below, SpyUserStore maintains the state of the number of times a function got called and throws an exception if the function gets called more than once within the scope of the test case.
  1. public class SpyUserStore : IUserStore
  2. {
  3. private static int Counter { get; set; }
  4. public SpyUserStore()
  5. {
  6. Counter = 0;
  7. }
  8. public string GetUserRole(string username)
  9. {
  10. if (Counter >= 1)
  11. throw new Exception("Function called more than once");
  12. Counter++;
  13. if (username == "admin")
  14. return "administrator";
  15. else
  16. return "contributor";
  17. }
  18. }

Mock

As shown below, I have set up the mock object of IUserStore which behaves differently for different inputs.
  1. Mock<IUserStore> mockedUserStore=new Mock<IUserStore>();
  2. mockedUserStore.Setup(func => func.GetUserRole("admin")).Returns("administrator");
  3. mockedUserStore.Setup(func => func.GetUserRole("user1")).Returns("contributor");
  4. mockedUserStore.Setup(func => func.GetUserRole("user2")).Returns("basic");

Which one shall I use?