MoqMeUp
An easy to use ioc like container that mocks (using Moq) all the class dependencies.
Why
You probably saw/created a class like this right ?
public class UserService : IUserService
{
private readonly IUserApiServices userApiServices;
private readonly ICoolUserService coolUserService;
private readonly ILogger logger;
public UserService(
IUserApiServices userApiServices,
ICoolUserService coolUserService,
ILogger logger)
{
this.userApiServices = userApiServices;
this.coolUserService = coolUserService
this.logger = logger;
}
public async Task<User> CreateUserAsync(CreateUserRequest r)
{
// All the magic code
var createdUser = await this.userApiServices.CreateUserAsync(r);
return createdUser;
}
}
Normally in your tests you need to create the mocks by yourself in every test, doing that setup a lot of times, which is error prone. Then when you need to add new dependencies to a class, then you'll need to refactor all the tests to support the new dependency.
(ノಠ益ಠ)ノ彡┻━┻
[TestClass]
public class UserServiceTests
{
[TestMethod]
[ExpectedException(typeof(ApiException))]
public async Task CreateUserAsync_WhenUserIsAlreadyRegistered_ShouldThrowApiException()
{
// Arrange
var userApiServicesMock = new Mock<IUserApiServices>();
var coolUserApiServicesMock = new Mock<ICoolUserService>();
var loggerMock = new Mock<ILogger>();
userApiServicesMock.Setup(x => x.CreateUserAsync(It.IsAny<CreateUserRequest>())
.ThrowsAsync(new ApiException("User is already registered"));
var target = new UserService(
userApiServicesMock.Object,
coolUserApiServicesMock.Object,
loggerMock.Object);
// Act
var act = await target.CreateUserAsync(new CreateUserRequest()
{
email = "sam@portugal.pt",
password = "random"
});
}
}
Thats when MoqMeUp comes handy ◔ᴗ◔
How to use
// Create a test class and make it inherit the MoqMeUp class:
[TestClass]
public class UserServiceTests : MoqMeUp<UserDataService>
{
[TestMethod]
[ExpectedException(typeof(ApiException))]
public async Task CreateUserAsync_WhenUserIsAlreadyRegistered_ShouldThrowApiException()
{
// Arrange
this.Get<IApiServices>()
.Setup(x => x.CreateUserAsync(It.IsAny<CreateUserRequest>())
.ThrowsAsync(new ApiException("User is already registered"));
var target = this.Build();
// Act
var act = await target.CreateUserAsync(new CreateUserRequest()
{
email = "sam@portugal.pt",
password = "random"
});
}
}
Or
// Create a MoqMeUp Container and build the class that you want to test from it:
[TestClass]
public class UserServiceTests
{
[TestMethod]
[ExpectedException(typeof(ApiException))]
public async Task CreateUserAsync_WhenUserIsAlreadyRegistered_ShouldThrowApiException()
{
var userServiceTestsMoqContainer = new MoqMeUp<UserDataService>();
// Arrange
userServiceTestsMoqContainer.Get<IApiServices>()
.Setup(x => x.CreateUserAsync(It.IsAny<CreateUserRequest>())
.ThrowsAsync(new ApiException("User is already registered"));
var target = userServiceTestsMoqContainer.Build();
// Act
var act = await target.CreateUserAsync(new CreateUserRequest()
{
email = "sam@portugal.pt",
password = "random"
});
}
}
Features
Get
When there is only one dependency with that type you can use the Get to retrieve the mocked dependency.
public class UserService : IUserService
{
private readonly IUserApiServices userApiServices;
public UserService(IUserApiServices userApiServices)
{
this.userApiServices = userApiServices;
}
// The rest of the code goes here
}
[TestClass]
public class UserServiceTests : MockMeUp<UserService>
{
public void GetUser_WhenUserExists_ShouldReturnIt()
{
this.Get<IUserApiServices>()
.Setup(x => x.GetUser(1))
.Returns(TestUsers.CoolUser);
var target = this.Build();
// The rest of the code goes here
}
}
Get(string name)
When there is more than one dependency with that type you can use the Get(string name) to retrieve the mocked dependency.
public class UserService : IUserService
{
private readonly IUserApiServices userApiServices;
private readonly IUserApiServices userApiServicesTwo;
public UserService(IUserApiServices userApiServices, IUserApiServices userApiServicesTwo)
{
this.userApiServices = userApiServices;
this.userApiServicesTwo = userApiServicesTwo;
}
// The rest of the code goes here
}
[TestClass]
public class UserServiceTests : MockMeUp<UserService>
{
public void GetUser_WhenUserExists_ShouldReturnIt()
{
this.Get<IUserApiServices>("userApiServices")
.Setup(x => x.GetUser(1))
.Returns(TestUsers.CoolUser);
var target = this.Build();
// The rest of the code goes here
}
}
GetLazy()
When there is a lazy dependency, you can configure the mock of its value
public class UserService : IUserService
{
private readonly Lazy<IUserApiServices> userApiServices;
public UserService(Lazy<IUserApiServices> userApiServices)
{
this.userApiServices = userApiServices;
}
// The rest of the code goes here
}
[TestClass]
public class UserServiceTests : MockMeUp<UserService>
{
public void GetUser_WhenUserExists_ShouldReturnIt()
{
this.GetLazy<IUserApiServices>()
.Setup(x => x.GetUser(1))
.Returns(TestUsers.CoolUser);
var target = this.Build();
// The rest of the code goes here
}
}
GetLazy(string name)
Same as GetLazy(), but here you can specify the dependency name (if there is more than one, or because you want)
GetFunc()
When there is a func dependency, you can configure the mock of the result of the func
public class UserService : IUserService
{
private readonly Func<IUserApiServices> userApiServices;
public UserService(Func<IUserApiServices> userApiServices)
{
this.userApiServices = userApiServices;
}
// The rest of the code goes here
}
[TestClass]
public class UserServiceTests : MockMeUp<UserService>
{
public void GetUser_WhenUserExists_ShouldReturnIt()
{
this.GetFunc<IUserApiServices>()
.Setup(x => x.GetUser(1))
.Returns(TestUsers.CoolUser);
var target = this.Build();
// The rest of the code goes here
}
}
GetFunc(string name)
Same as GetFunc(), but here you can specify the dependency name (if there is more than one, or because you want)
Use(T dependency)
With Use you can define a custom value to the dependency, if you want to provide a dependency created by you. Thats a good way of configuring not mockable objects like integers etc.
public class UserService : IUserService
{
private readonly IUserApiServices userApiServices;
private readonly int int tenantId;
public UserService(IUserApiServices userApiServices, int tenantId)
{
this.userApiServices = userApiServices;
this.tenantId = tenantId;
}
// The rest of the code goes here
}
[TestClass]
public class UserServiceTests : MockMeUp<UserService>
{
public void GetUser_WhenUserExists_ShouldReturnIt()
{
this.Get<IUserApiServices>()
.Setup(x => x.GetUser(1))
.Returns(TestUsers.CoolUser);
this.Set<int>(20000);
var target = this.Build();
// The rest of the code goes here
}
}
Use(string name, T dependency)
Same as Use(), but here you set manually a dependency for a specify the dependency by name
public class UserService : IUserService
{
private readonly IUserApiServices userApiServices;
private readonly int int tenantId;
private readonly int int clientId;
public UserService(IUserApiServices userApiServices, int tenantId, int clientId)
{
this.userApiServices = userApiServices;
this.tenantId = tenantId;
this.clientId = clientId;
}
// The rest of the code goes here
}
[TestClass]
public class UserServiceTests : MockMeUp<UserService>
{
public void GetUser_WhenUserExists_ShouldReturnIt()
{
this.Get<IUserApiServices>()
.Setup(x => x.GetUser(1))
.Returns(TestUsers.CoolUser);
this.Set<int>("tenantId", 20000);
this.Set<int>("clientId", 1);
var target = this.Build();
// The rest of the code goes here
}
}