Is it useless to mock an interface's behavior if it's not to be called in the test - unit-testing

Do i need to mock interfaces that does not call, for instance user name and password field is empty? I'm trying to write test first but confused if mocks should be used.
My login test
private val authRepository: AuthRepository = mockk()
private val userManager: AccountManager = mockk()
private lateinit var authUseCase: AuthUseCase
#BeforeEach
fun setUp() {
clearMocks(authRepository)
clearMocks(userManager)
authUseCase = AuthUseCase(authRepository, userManager)
}
/**
* Scenario: Login check with empty fields:
* * Given I am on the login page
* * When I enter empty username
* And I enter empty password
* And I click on the "Login" button
* * Then I get empty fields error.
*/
#Test
fun `Empty fields result empty fields error`() {
// Given
// When
val expected = authUseCase.login("", "", false)
// Then
verify(exactly = 0) {
authRepository.login(or(any(), ""), or(any(), ""), any())
}
expected assertEquals EMPTY_FIELD_ERROR
}
Do i have to mock interface for the given part of the test or AccountManager even though they are not called since user name and/or fields are empty?
This is the final version of login method i intend to write after tests
class AuthUseCase(
private val authRepository: AuthRepository,
private val accountManager: AccountManager
) {
private var loginAttempt = 1
/*
STEP 1: Throw exception for test to compile and fail
*/
// fun login(
// userName: String,
// password: String,
// rememberMe: Boolean = false
// ): AuthenticationState {
// throw NullPointerException()
// }
/*
STEP3: Check if username or password is empty
*/
// fun login(
// userName: String,
// password: String,
// rememberMe: Boolean = false
// ): AuthenticationState {
//
//
// if (userName.isNullOrBlank() || password.isNullOrBlank()) {
// return EMPTY_FIELD_ERROR
// }else {
// throw NullPointerException()
// }
//
// }
/**
* This is the final and complete version of the method.
*/
fun login(
userName: String,
password: String,
rememberMe: Boolean
): AuthenticationState {
return if (loginAttempt >= MAX_LOGIN_ATTEMPT) {
MAX_NUMBER_OF_ATTEMPTS_ERROR
} else if (userName.isNullOrBlank() || password.isNullOrBlank()) {
EMPTY_FIELD_ERROR
} else if (!checkUserNameIsValid(userName) || !checkIfPasswordIsValid(password)) {
INVALID_FIELD_ERROR
} else {
// Concurrent Authentication via mock that returns AUTHENTICATED, or FAILED_AUTHENTICATION
val authenticationPass =
getAccountResponse(userName, password, rememberMe)
return if (authenticationPass) {
loginAttempt = 0
AUTHENTICATED
} else {
loginAttempt++
FAILED_AUTHENTICATION
}
}
}
private fun getAccountResponse(
userName: String,
password: String,
rememberMe: Boolean
): Boolean {
val authResponse =
authRepository.login(userName, password, rememberMe)
val authenticationPass = authResponse?.authenticated ?: false
authResponse?.token?.let {
accountManager.saveToken(it)
}
return authenticationPass
}
private fun checkUserNameIsValid(field: String): Boolean {
return field.length >15 && field.endsWith("#example.com")
}
private fun checkIfPasswordIsValid(field: String): Boolean {
return field.length in 6..10
}
}
Should i only mock when all other states and passed i get a mock response from repository and interaction with account manager occurs?
What should be given section of the test?
Edit:
I updated given section of this test to
#Test
fun `Empty fields result empty fields error`() {
// Given
every { authRepository.login(or(any(), ""), or(any(), "")) } returns null
// When
val expected = authUseCase.login("", "", false)
// Then
verify(exactly = 0) { authRepository.login(or(any(), ""), or(any(), "")) }
expected assertThatEquals EMPTY_FIELD_ERROR
}
Is there something wrong with this kind of behavior testing?

I would suggest that you don't need the verify in the "Empty fields result empty fields error" test. I would also suggest you write separate tests for each empty field. If you were doing strict TDD you would be testing each condition as you wrote the code. i.e.
'Empty username should error" would be the first test and the first condition tested, then "Empty password should error" the next (after you have done two separate written your second test your code may look like
if (userName.isNullOrBlank()) {
return EMPTY_FIELD_ERROR
}
if (password.isNullOrBlank() {
return EMPTY_FIELD_ERROR
}
Once both the tests above pass you could refactor to
if (userName.isNullOrBlank() || password.isNullOrBlank()) {
EMPTY_FIELD_ERROR
}
Once you start testing the conditional statements for checkUserNameIsValid and checkIfPasswordIsValid, you would need to introduce the authRepository and accountManager to your class (constructor injection) and then you would need to start mocking the calls as you use them. Generally mocking frameworks will fake an object (i.e. the code will run but won't return any meaningful result). You should aim to return actual mock data when you want to test specific behavior i.e. you should be returning a valid object from the authRepository.login when you are testing for a successful login. Generally I stay away from using setup methods in the #BeforeEach and use either a factory method or builder to create my class under test. I am unfamiliar with the kotlin syntax so can at best do some sudo code to demonstrate how your builder or factory functions may look like.
// overloaded factory function
fun create() {
val authRepository: AuthRepository = mockk()
val userManager: AccountManager = mockk()
return AuthUseCase(authRepository, userManager);
}
fun create(authRepository: AuthRepository) {
val userManager: AccountManager = mockk()
return AuthUseCase(authRepository, userManager);
}
fun create(authRepository: AuthRepository, userManager: AccountManager) {
return AuthUseCase(authRepository, userManager);
}
You will need to have a look at how to create a builder in kotlin but the end result you would be looking for is that the builder always starts setting the dependencies for you class under test as mocks that do nothing but allows you to change those mocks.
e.g.
AuthUseCase authUseCase = AuthUseCaseBuilder.Create().WithAuthRepository(myMockAuthRepository).Build();
One final thing. I purposely left out discussing loginAttempt check above as to me it looks like the AuthUseCase is a service class that will be used by multiple users and live for the lifetime of the request in which case you don't want to maintain state within the class (i.e. the loginAttempt variable has the same lifetime as the class). It would be better to record the attempts per username in a database table and the attempt count would need to be reset after each successful login.
Hope this helps.

Related

How to test code before a suspended coroutine function

Consider the following example in a view model class:
override fun signInViewSelected(
email: String,
password: String
) {
viewModelScope.launch {
loadingViewState.value = LoadingState.Loading("Loading")
withContext(dispatcher.ioDispatcher) {
authManager.signIn(email, password) // suspend fun signIn(email: String, password: String): Boolean -> makes network call
}
loadingViewState.value = LoadingState.NotLoading
}
}
How could I test this method so that I can verify that I start out in loading state, call the authManager.signIn method, and then end up in the not loading state?
When I had this setup with completion handlers I was able to capture the argument passed to my mock authManager class, and then call that manually to advance the completion, but with coroutines I'm not familiar with how to do the equivalent behavior.
What I'd want is something like this, ideally:
#Test
fun `sign in loading state`() {
signInViewModel.signInViewSelected("email#email.com", "password")
val inProgressLoadingViewState = signInViewModel.loadingViewState.getOrAwaitValue()
assertLoadingStateIsLoading(inProgressLoadingViewState, progressMessage)
// delay mockAuthManager until now, have it execute at this point
val finishedLoadingViewState = signInViewModel.loadingViewState.getOrAwaitValue()
assertLoadingStateIsNotLoading(finishedLoadingViewState)
}
Any thoughts?
Assuming you're familiar with libraries like AssertJ and Mockito, I would go about it the following way:
First off, mock the observer of loadingViewState (assuming you have some LiveData in place) and authManager:
private lateinit var viewModel: SomeViewModel
private val loadingViewStateObserver = mock<Observer<LoadingViewState>>()
fun initViewModel() {
viewModel = SomeViewModel().apply {
loadingViewStateLiveData.observeForever(loadingViewStateObserver)
}
}
#Test
fun `sign in loading state`() {
runBlocking {
initViewModel()
viewModel.signInViewSelected("email", "password")
inOrder(loadingViewStateObserver, authManager) {
verify(loadingViewStateObserver).onChanged(LoadingState.NotLoading)
verify(authManager).signIn("email", "password")
verify(loadingViewStateObserver).onChanged(LoadingState.Loading("Loading"))
}
}
}

Unit Test NService.Send from an API Controller

I have an API Controller which publishes a command using NServiceBus. I am using NUnit and NSubstitute for testing. I want to test that certain properties from the model are populated on the command
Here is my controller with a route.
[RoutePrefix("api/fileService")]
public class FileServiceController : ApiController
{
[HttpPost]
[Route("releasefile")]
public async Task<IHttpActionResult> ReleaseFile(FileReleaseAPIModels.ReleaseFileModel model)
{
var currentUser = RequestContext.Principal?.Identity as ClaimsIdentity;
if (model.FileType.Equals("ProductFile"))
{
_logger.Info($"Releasing Product files for date: {model.FileDate.ToShortDateString()} ");
_bus.Send<IReleaseProductFiles>("FileManager.Service", t =>
{
t.FileId = Guid.NewGuid();
t.RequestedDataDate = model.FileDate;
t.RequestingUser = currentUser?.Name;
t.RequestDateTime = DateTime.Now;
});
}
return Ok();
}
}
In my test, I substitute(mock) Ibus and try to validate the call received. Here is the test method:
[Test]
public async Task TestReleaseProductsFile()
{
var bus = Substitute.For<IBus>();
var dbContent = _container.Resolve<IFileManagerDbContext>();
var apiContext = new FileServiceController(bus, dbContent);
//Create a snapshot
var releaseDate = DateTime.Now.Date;
var result = await apiContext.ReleaseFile(new ReleaseFileModel
{
FileDate = releaseDate,
FileType = "ProductFile"
});
Assert.That(result, Is.Not.Null, "Result is null");
Assert.That(result, Is.TypeOf<OkResult>(), "Status code is not ok");
bus.Received(1)
.Send<IReleaseProductFiles>(Arg.Is<string>("FileManager.Service"), Arg.Is<Action<IReleaseProductFiles>>(
action =>
{
action.FileId = Guid.NewGuid();
action.RequestedDataDate = releaseDate;
action.RequestingUser = String.Empty;
action.RequestDateTime = DateTime.Now;
}));
}
This results in error - even though the message is actually sent. Here is the error message:
NSubstitute.Exceptions.ReceivedCallsException : Expected to receive exactly 1 call matching:
Send<IReleaseProductFiles>("Capelogic.Service", Action<IReleaseProductFiles>)
Actually received no matching calls.
Received 1 non-matching call (non-matching arguments indicated with '*' characters):
Send<IReleaseProductFiles>("Capelogic.Service", *Action<IReleaseProductFiles>*)
I am obviously missing something obvious here.
The problem here is with the Action<IReleaseProductFiles> argument to Send -- we can't automatically tell if two different actions are the same. Instead, NSubstitute relies on the references being equivalent. Because both the test and the production code create their own Action instance, these will always be different and NSubstitute will say the calls don't match.
There are a few different options for testing this. These examples relate to Expression<Func<>>, but the same ideas apply to Action<>s.
In this case I'd be tempted to test this indirectly:
[Test]
public async Task TestReleaseProductsFile()
{
var bus = Substitute.For<IBus>();
var returnedProductFiles = Substitute.For<IReleaseProductFiles>();
// Whenever bus.Send is called with "FileManager.Service" arg, invoke
// the given callback with the `returnedProductFiles` object.
// We can then make sure the action updates that object as expected.
bus.Send<IReleaseProductFiles>(
"FileManager.Service",
Arg.Invoke<IReleaseProductFiles>(returnedProductFiles));
// ... remainder of test ...
Assert.That(result, Is.TypeOf<OkResult>(), "Status code is not ok");
Assert.That(returnedProductFiles.FileId, Is.Not.EqualTo(Guid.Empty));
Assert.That(returnedProductFiles.RequestedDataDate, Is.EqualTo(releaseDate));
Assert.That(returnedProductFiles.RequestingUser, Is.EqualTo(String.Empty));
}
I'd recommend having a look through the previously mentioned answer though to see if there is a better fit for your situation.

Mocking in Unit Tests

I am trying to test the AddCategory of the following CategoryService.
My problem is that I am having a hard time understanding what to mock/fake.
My attempt at the test is at the bottom.
I am using MOQ, xUnit and FluentAssertions.
I am using FluentValidation for the validators.
Category Service
public class CategoryService : ValidatingServiceBase, ICategoryService
{
private readonly IUnitOfWork unitOfWork;
private readonly IRepository<Category> categoryRepository;
private readonly IRepository<SubCategory> subCategoryRepository;
private readonly IValidationService validationService;
public CategoryService(
IUnitOfWork unitOfWork,
IRepository<Category> categoryRepository,
IRepository<SubCategory> subCategoryRepository,
IValidationService validationService)
: base(validationService)
{
this.unitOfWork = unitOfWork;
this.categoryRepository = categoryRepository;
this.subCategoryRepository = subCategoryRepository;
this.validationService = validationService;
}
public bool AddCategory(Category category)
{
var validationResult = validationService.Validate(category);
if (!validationResult.IsValid)
{
return false;
}
else
{
categoryRepository.Add(category);
return true;
}
}
public bool DoesCategoryExist(string categoryName)
{
return categoryRepository.Query().SingleOrDefault(x => x.Name == categoryName) != null;
}
}
Validation Service
public class ValidationService : ServiceBase, IValidationService
{
private readonly IValidatorFactory validatorFactory;
public ValidationService(IValidatorFactory validatorFactory)
{
Enforce.ArgumentNotNull(validatorFactory, "validatorFactory");
this.validatorFactory = validatorFactory;
}
public ValidationResult Validate<TEntity>(TEntity entity) where TEntity : class
{
var validator = validatorFactory.GetValidator<TEntity>();
return validator.Validate(entity);
}
}
Validator Factory
public class ValidatorFactory : IValidatorFactory
{
public IValidator GetValidator(Type type)
{
Enforce.ArgumentNotNull(type, "type");
return DependencyResolver.Current.GetService(typeof(IValidator<>).MakeGenericType(type)) as IValidator;
}
public IValidator<T> GetValidator<T>()
{
return DependencyResolver.Current.GetService<IValidator<T>>();
}
}
Category Validator
public class CategoryValidator : AbstractValidator<Category>
{
public CategoryValidator(ICategoryService service)
{
RuleFor(x => x.Name)
.NotEmpty()
.Must((category, name) =>
{
return service.DoesCategoryExist(name);
});
}
}
Unit Test Attempt
[Fact]
public void AddCategory_Should_ReturnTrue()
{
var category = new Category() { Name = "Cat1" };
var unitOfWork = new Mock<IUnitOfWork>();
var categoryRepo = new Mock<IRepository<Category>>();
var subCategoryRepo = new Mock<IRepository<SubCategory>>();
var mockCategoryService = new Mock<ICategoryService>();
var categoryValidator = new CategoryValidator(mockCategoryService.Object);
var validatorFactory = new Mock<IValidatorFactory>();
validatorFactory.Setup(x => x.GetValidator<CategoryValidator>()).Returns(categoryValidator as IValidator<CategoryValidator>);
var validationService = new ValidationService(validatorFactory.Object);
var categoryService = new CategoryService(
unitOfWork.Object,
categoryRepo.Object,
subCategoryRepo.Object,
validationService);
categoryService.AddCategory(category);
}
Well for the AddCategory method, I think you really only need two mocks, one for the ValidationService, and one for the CategoryRepository, because the other dependencies aren't exercised in that function and therefore are irrelevant
(the story might be different of course if your ctor throws on null arguments but in this case I think you are OK - albeit you might consider adding these checks in the future :)
Anyway, being pedantic, I'd nearly be inclined to write two (or more - maybe one for null input to verify it throws or returns false or whatever) "unit" tests for this function;
One to verify that given an invalid category, the function returns false,
One to verify that given a valid category, the function calls Add on the CategoryRepository dependency.
So it would look like this (sorry, this is using MSTest syntax as I'm not familiar with xUnit but it's the same idea). Also have not tested below for typos, etc :)
public void AddCategory_InvalidCategory_ShouldReturnFalse()
{
//Arrange
var mockValidator = new Mock<IValidator>();
//no matter what we pass to the validator, it will return false
mockValidator.Setup(v=>v.Validate(It.IsAny<Category>()).Returns(false);
var sut= new CategoryService(null,null,null,mockValidator.Object);
bool expected = false;
//ACT
bool actual = sut.AddCategory(new Category());
//ASSERT
Assert.AreEqual(expected,actual,"Validator didn't return false as expected");
}
public void AddCategory_ValidCategory_ShouldCallRepositoryAdd()
{
//Arrange
var mockValidator = new Mock<IValidator>();
//no matter what we pass to the validator, it will return true
mockValidator.Setup(v=>v.Validate(It.IsAny<Category>()).Returns(true);
var mockRepo = new Mock<IRepository<SubCategory>>();
mockRepo.Setup(r=>r.Add(It.IsAny<Category>())); //do not know or care what happens as this is a void method.
var sut= new CategoryService(null,mockRepo.Object,null,mockValidator.Object);
bool expected = false;
//ACT
bool actual = sut.AddCategory(new Category());
//ASSERT
mockRepo.Verify(r=>r.Add(It.IsAny<Category>(),Times.Exactly(1),"Repo ADD method not called or called too many times, etc");
Assert.AreEqual(expected,actual,"Add was called BUT the AddCategoryMethod didn't return true as expected"); //and of course you could be totally pedantic and create a new test method for that last assert ;)
}
The reason I favour this approach is because it forces you to consider the behaviour of the method under test, as well as ensuring that you don't involve any dependencies that are not being tested plus it means your test methods only create exactly what they need to in order to run the tests (and of course you can create some setup/teardown helpers to pre-create those mocks for you);
Of course you could put all the above into a single method but for the sake of saving a few LOC I hope you'll agree that having two separate tests to verify two separate behaviours is a more robust approach.
Just my 2c. hope it helps!

How to Include associated entities

I want to create test case for below method "GetByEmail".
public User GetByEmail(string email, bool includeUserRoles = false, bool includeUserType = false)
{
Expression<Func<User>> whereClause = u => u.Email == email;
return GetQuery(whereClause, includeUserRoles, includeUserType) .FirstOrDefault();
}
private IQueryable<User> GetQuery(Expression<Func<User>> whereClause,
bool includeUserRoles = false, bool includeUserType = false)
{
IQueryable<User> query = base.GetQuery(whereClause);
if (includeUserRoles)
query = query.Include(u => u.UserRoles);
if (includeUserType)
query = query.Include(u => u.UserType);
return query;
}
protected IQueryable<T> GetQuery<T>(Expression<Func<T>> predicate) where T : EntityBase
{
return predicate != null ?
CreateObjectSet<T>().Where(predicate) :
CreateObjectSet<T>();
}
protected IObjectSet<T> CreateObjectSet<T>() where T : EntityBase
{
return _context.CreateObjectSet<T>();
}
public static IQueryable<T> Include<T>(this IQueryable<T> source, Expression<Func<T>> property)
{
var objectQuery = source as ObjectQuery<T>;
if (objectQuery != null)
{
var propertyPath = GetPropertyPath(property);
return objectQuery.Include(propertyPath);
}
return source;
}
Below is my test case method -
[Fact]
private void GetByEmail_PassedEmailAddress_RelatedUser()
{
//Created fake context
var fakeContext = Isolate.Fake.Instance<Entities>();
//Created fake Repository and passed fakeContext to it
var fakeRepository = Isolate.Fake.Instance<Repository>(Members.CallOriginal, ConstructorWillBe.Called, fakeContext);
//Created fake in memory collection of User
var fakeUsers = GetUsers();
Isolate.WhenCalled(() => fakeContext.Context.CreateObjectSet<User>())
.WillReturnCollectionValuesOf(fakeUsers);
var User = Isolate.Invoke.Method(fakeRepository, "GetByEmail", "abc#xyz.com", true, true);
Assert.True(User != null);
}
In the above test case method I successfully get the user with passed email but not able to include other entities of associated user.
Kindly let me know, how can I include other entities with associated User.
Include is leaky abstraction - it works only with EF and linq-to-entities and cannot be successfully used with linq-to-objects. You know that your unit test needs populated relations so your GetUsers method must prepare that data. That is a point of mocking / faking - you don't think about internal implementation of mocked method. You simply return what should be returned.
Btw. what is the point of your test? It looks like you are trying to test a mock - that is wrong. Mock provides correct data and you only need it to test another feature dependent on mocked component.

Unit testing custom validator of command object with dependency

I have a command object for registering user, and I want to check how old is the user. This command object has a service dependency. How can I test custom validator for my dateOfBirth property? As it looks now is taken straight from documentation, here.
class RegisterUserCommand {
def someService
String username
String password
String password2
String email
Date dateOfBirth
static constraints = {
// other constraints
dateOfBirth blank: false, validator: {val, obj ->
return obj.someService.calculateAge(val) >= 18
}
}
So basically the question is: how can I mock 'obj' parameter of the validator closure?
The easiest way to test validation on a command object is to use GrailsUnitTestCase.mockForConstraintsTests. A mock validate method will be applied to your command object, and you can just call validate() like you would outside of a test.
Here's an example of how you could write your unit test. The blank constraint isn't meaningful for dates, so I've changed it to nullable: false.
import grails.test.GrailsUnitTestCase
class RegisterUserCommandTests extends GrailsUnitTestCase {
RegisterUserCommand cmd
protected void setUp() {
super.setUp()
cmd = new RegisterUserCommand()
mockForConstraintsTests RegisterUserCommand, [cmd]
}
void testConstraintsNull() {
cmd.dateOfBirth = null
cmd.someService = [calculateAge: { dob -> 18 }]
def result = cmd.validate()
assert result == false
assert cmd.errors.getFieldErrors('dateOfBirth').code == ['nullable']
}
void testConstraintsCustom() {
cmd.dateOfBirth = new Date()
cmd.someService = [calculateAge: { dob -> 17 }]
def result = cmd.validate()
assert result == false
assert cmd.errors.getFieldErrors('dateOfBirth').code == ['validator.invalid']
}
}
Note that your service won't get injected in a unit test (it will in an integration test though), so you'll either need to mock it, as above, or create an instance and assign it to cmd.someservice.