Expect call is not working on mock - c#

I am writing test for CheckPassWord()
I presume the Expect call is not behaving as expected on my userMangerMock.
//CheckPassword returns true if the parameter matches to the exsting user.
//Existing user is obtained by GetUser() by internal call
bool passWordMatch = userMangerMock.CheckPassword(userInfo.Id, userInfo.Password);
CheckPassWord() internally calls GetUser(),
Since GetUser() needs more deeper internal calls I decided to return a stubUser
I believe implementation of Expect() is sufficient for that.
Note that the following call var userInfo = userMangerMock.GetUser("TestManager");is returning stubUser.
But , CheckPassword() call I am assuming the stubUser is not returned thus the test failing.
Correct me if any bug in the following UT.
//Use TestInitialize to run code before running each test
[TestInitialize()]
public void MyTestInitialize()
{
CreateUser();
}
private static IUser _stubUser;
public void CreateUser()
{
IUserFactory iUserFactory = new UserFactory();
UserParams parameters = new UserParams();
parameters.Password = "TestPassword123!";
parameters.UserID = "TestManager";
_stubUser = iUserFactory.CreateUser(parameters);
}
/// <summary>
///A test for CheckPassword
///</summary>
[TestMethod( )]
public void CheckPasswordTest()
{
// !!! Below I've used WhenCalled() to show you that correct
// expectation is called based on argument type, just see in debugger
IUserManager userMangerMock = MockRepository.GenerateMock<IUserManager>();
userMangerMock.Expect(x => x.GetUser(Arg<string>.Is.Anything))
.WhenCalled((mi) =>
{
Debug.WriteLine("IUserManager - string parameter");
})
.Return(_stubUser);
var userInfo = userMangerMock.GetUser("TestManager");
bool passWordMatch = userMangerMock.CheckPassword(userInfo.Id, userInfo.Password);
userMangerMock.VerifyAllExpectations();
Assert.AreEqual(true, passWordMatch);
}
/// <summary>
/// Returns true if password matches the user
/// </summary>
public bool CheckPassword(string userId, string password)
{
if (userId == null)
{
throw new ArgumentNullException("userId");
}
IUser user = GetUser(userId);
if (user == null)
{
throw new UserManagementException(UserManagementError.InvalidUserId);
}
return (user.Password == password);
}

A couple of things I noticed in your test:
userMangerMock.VerifyAllExpectations();
This will always pass since you are manually calling GetUser() in the test code itself:
var userInfo = userMangerMock.GetUser("TestManager");
So you can actually remove this verify call, since it's not needed.
It feels like your unit test does not seem to provide any value to you, since it's asserting on a hard-coded mock object.
var userInfo = userMangerMock.GetUser("TestManager");
bool passWordMatch = userMangerMock.ChePassword(userInfo.Id, userInfo.Password);
Assert.AreEqual(true, passWordMatch);
If userInfo is a reference to the stub object _stubUser then you're unit test can be refactored to:
bool passWordMatch = userMangerMock.CheckPassword(_stubUser.Id, _stubUser.Password);
Assert.AreEqual(true, passWordMatch);

Related

Mock a method from another class called from a mocked method

We are creating unit tests for an application and ran into a problem creating certain tests.
We are unit testing the following Handle() method of the class ActivateCommandHandler:
public class ActivateCommand : IRequest<HttpResponseMessage>
{
public string Controller { get; set; }
public ActivateCommand(string controllername)
{
this.Controller = controllername;
}
}
public class ActivateCommandHandler : CommandHandler<ActivateCommand, HttpResponseMessage>
{
protected readonly ICommandsGateway _commandsGateway;
protected readonly EndpointSettings _endpoints;
protected readonly IUserProfile _userprofile;
public ActivateCommandHandler(IMediator mediator, ICommandsGateway commandsGateway, IOptions<EndpointSettings> endpoints, IValidationContext validationContext, IUserProfile currentUser) : base(mediator, validationContext, currentUser)
{
_commandsGateway = commandsGateway;
_endpoints = endpoints.Value;
_userprofile = currentUser;
}
public override async Task<HttpResponseMessage> Handle(ActivateCommand command, CancellationToken cancellationToken)
{
if (_endpoints.EndpointExists(command.Controller))
{
// Check whether the second server controller is deactivated
string peercontroller = _endpoints.GetPeerController(command.Controller);
if (!string.IsNullOrEmpty(peercontroller))
{
BaseRedundancySwitchStatus controllerStatus = await _commandsGateway.GetRedundancySwitchStatus(_endpoints.GetEndpointAddress(peercontroller));
if ((controllerStatus.CurrentState == "Activated") || (controllerStatus.CurrentState == "ActivatedWithWarning") || (controllerStatus.CurrentState == "Activating"))
{
var resp = new HttpResponseMessage(HttpStatusCode.Conflict)
{
Content = new StringContent($"{peercontroller},{controllerStatus.CurrentState}")
};
return resp;
}
}
var result = await _commandsGateway.PostActivateCommand(_endpoints.GetEndpointAddress(command.Controller));
return result;
}
else
{
throw new InvalidControllerNameException($"ERROR: The controller {command.Controller} does not exist as an endpoint on this Control Center!");
}
}
}
For this the following were mocked: _endpoints, command and _commandsGateway (interface). This works great for unit testing the parameter validation. But we now want to test the behaviour when the peercontroller status is set to a specific value.
To do this we are trying to mock out the function _commandsGateway.GetRedundancySwitchStatus(). The following is the actual test implementation. We mock the _commandsGateway.GetRedundancySwitchStatus() function to return the expected BaseRedundancySwitchStatus with CurrentState set to "Activated". After that we call the handler of the actual function to be tested and check whether we get the expected error.
[Fact]
public async void ShouldHaveErrors_PeerControllerStateActivated()
{
var command = new ActivateCommand("Server Controller Slave1");
BaseRedundancySwitchStatus result = new BaseRedundancySwitchStatus()
{
CurrentState = "Activated"
};
_commandsGateway
.Setup(s => s.GetRedundancySwitchStatus("Server Controller Slave1"))
.ReturnsAsync(result);
HttpResponseMessage res = await _handler.Handle(command, CancellationToken.None);
Assert.True(res.StatusCode == System.Net.HttpStatusCode.Conflict);
}
Debugging the code, when I step through the code in the Handle() method where _commandsGateway.GetRedundancySwitchStatus is called, I can see that _endpoints.GetEndpointAddress(command.Controller) (which is the parameter) is called and the correct value is returned. After this the debugger steps to the next line without any indication of having executed the mock GetRedundancySwitchStatus() function. Inspecting the controllerStatus variable the value is null. I would expect the value to be the BaseRedundancySwitchStatus object which is supposed to be returned by the mocked GetRedundancySwitchStatus() function.
Where are we going wrong?

How to skip Fluent validation static function during unit testing?

I am using xunit with Moq and testing other functionality in one function but i always get an exception from Fluent Validation extension methods which I can not bypass.
This is original code
public class AdService : IAdService
{
private readonly IValidator<AdToSearchDto> _adToSearchDtoValidator;
public AdService(IValidator<AdToSearchDto> addToSearchDtoValidator)
{
_adToSearchDtoValidator = addToSearchDtoValidator
}
public async Task<AdsToReturnDto> GetAdsAsync(AdToSearchDto searchDto)
{
_adToSearchDtoValidator.ValidateAndThrow(searchDto); // This line always throw exception
return await _adRepository.GetUserAdsAsync(searchDto, userId, user?.Country);
}
}
Unit test class
[Fact]
public async Task Ads_Can_Searched_By_UserId()
{
var validator = new Mock<IValidator<AdToSearchDto>>();
var adService = new AdService(validator.Object);
var adService = new AdService(validator.Object );
var ads = DataGenerator.CreateAds(2);
ads[0].UserId = searchingUserId;
ads[1].UserId = anotherUserId;
await adRepository.CreateAdAsync(ads[0]);
await adRepository.CreateAdAsync(ads[1]);
var result = await adService.GetAdsAsync( adToSearchDto, Guid.Empty ) ;
result.Ads.Count.Should().Be(1);
result.Ads.FirstOrDefault()?.UserId.Should().Be(searchingUserId.ToString());
}
I cant bypass
ValidateAndThrow
as this is extension method.
Is there any way to bypass ValidateAndThrow method in unit test ?
Edited:
Error i am getting
System.NullReferenceException : Object reference not set to an instance of an object.
at FluentValidation.DefaultValidatorExtensions.ValidateAndThrow[T](IValidator`1 validator, T instance, String ruleSet) in C:\Projects\FluentValidation\src\FluentValidation\DefaultValidatorExtensions.cs:line 943
at Market.Business.Ad.AdService.GetAdsAsync(AdToSearchDto searchDto, Guid userId) in C:\Users\Shahid Abdullah\Projects\MyStuff.IdentityServer\src\Market\Market.Business\Ad\AdService.cs:line 129
at Market.Test.Ad.AdTests.Ads_Can_Searched_By_UserId() in C:\Users\Shahid Abdullah\Projects\MyStuff.IdentityServer\src\Market\Market.Test\Ad\AdTests.cs:line 100
--- End of stack trace from previous location where exception was thrown ---
Exception in source code
public static void ValidateAndThrow<T>(
this IValidator<T> validator,
T instance,
string ruleSet = null)
{
ValidationResult validationResult = validator.Validate<T>(instance, (IValidatorSelector) null, ruleSet);
if (!validationResult.IsValid) // this line throws exception as validationResult is null
throw new ValidationException((IEnumerable<ValidationFailure>) validationResult.Errors);
}
/// <summary>
/// Performs validation and then throws an exception if validation fails.
/// </summary>
/// <param name="validator">The validator this method is extending.</param>
/// <param name="instance">The instance of the type we are validating.</param>
/// <param name="ruleSet">Optional: a ruleset when need to validate against.</param>
public static void ValidateAndThrow<T>(this IValidator<T> validator, T instance, string ruleSet = null) {
var result = validator.Validate(instance, ruleSet: ruleSet);
if (!result.IsValid) {
throw new ValidationException(result.Errors);
}
}
Source
ValidateAndThrow expects a result to be return from the validator when invoked.
Because there is no result from the mock
if (!result.IsValid) {...
throws a null reference exception.
Setup the mock to behave as expected when the extension method is invoked while exercising the test
[Fact]
public async Task Ads_Can_Searched_By_UserId() {
//Arrange
var validator = new Mock<IValidator<AdToSearchDto>>();
var validResult = new ValidationResult();
validator
.Setup(_ => _.Validate(It.IsAny<ValidationContext>())
.Returns(validResult);
var adService = new AdService(validator.Object);
//...
}

Does my unit test care about too much

I have 2 concerns about my unit test method:
Do I test too much in one test method?
How can my test method name reflect all test expectations?
I asked myself when my method name says: ReturnInvalidModelState, then my 2 other Asserts are not correct. At least concerning the method name...
[Test]
public void Create_TemplateAlreadyExists_ReturnInvalidModelState()
{
// ARRANGE
TemplateViewModel templateViewModel = new TemplateViewModel {
Name = "MyTest"
};
Mock<ITemplateDataProvider> mock1 = new Mock<ITemplateDataProvider>();
Mock<IMappingEngine> mock2 = new Mock<IMappingEngine>();
TemplateController controller =
new TemplateController(mock1.Object, mock2.Object);
mock1.Setup(m => m.TemplateExists("MyTest")).Returns(true);
// Set ModelState.IsValid to false
controller.ModelState.AddModelError("Name",
"This name already exists.");
// ACT
ActionResult result = controller.Create(templateViewModel);
// ASSERT
Assert.IsFalse(controller.ModelState.IsValid);
Assert.IsInstanceOfType(typeof(PartialViewResult), result);
Assert.AreEqual(templateViewModel, ((PartialViewResult)result).Model);
}
[HttpPost]
public ActionResult Create(TemplateViewModel templateViewModel)
{
if (ModelState.IsValid
&& !_templateDataProvider.TemplateExists(templateViewModel.Name))
{
Template template =
Mapper.Map<TemplateViewModel, Template>(templateViewModel);
_templateDataProvider.AddTemplate(template);
return new JsonNetResult(new { success = true });
}
ModelState.AddModelError("Name", "This name already exists.");
return PartialView(templateViewModel);
}
Yes, I think that you are testing for too many things.
Start with renaming your test method. Your method signature should describe action, scenario and expected outcome.
If I were to rename your method, than I would end up with the following:
public void Create_DuplicateTemplate_ModelStateIsInvalidAndReturnsPartialViewResultAndPartialViewResultOfTypeTemplateViewModel()
{
}
Your test is concerned with three things, rather than one. When it fails, you won't know straight away why it has failed.
Consider re-factoring this into smaller tests and encapsulating some of the arrangement logic so that it can be re-used.
Edit:
You made a good point in your comment regarding single test method having a single assertion. I agree with you on that one, as good as it sounds, often it's not sufficient.
Say I have the following action method:
[HttpPost]
public ActionResult Register(NewUserViewModel newUser)
{
if (!ModelState.IsValid)
return View(newUser);
var newUserDTO = Mapper.Map<NewUserViewModel, NewUserDTO>(newUser);
var userDTO = UserManagementService.RegisterUser(newUserDTO);
var result = Mapper.Map<UserDTO, UserViewModel>(userDTO);
TempData.Add("RegisteredUser", result);
return RedirectToAction("RegisterSuccess");
}
I have the following unit test for this method:
[TestMethod]
public void Register_HttpPost_ValidViewModel_ReturnsRegisterSuccess()
{
// Arrange
var autoMapperMock = this.mockRepository.DynamicMock<IMapper>();
var userManagementServiceMock = this.mockRepository.DynamicMock<IUserManagementService>();
var invalidRegistrationViewModel = new NewUserViewModel
{
LastName = "Lastname",
FirstName = "Firstname",
Username = null
};
autoMapperMock.Expect(a => a.Map<UserDTO, UserViewModel>(Arg<UserDTO>.Is.Anything)).Repeat.Once().Return(null);
autoMapperMock.Expect(a => a.Map<NewUserViewModel, NewUserDTO>(Arg<NewUserViewModel>.Is.Anything)).Repeat.Once().Return(null);
userManagementServiceMock.Expect(s => s.RegisterUser(Arg<NewUserDTO>.Is.Anything)).Repeat.Once();
autoMapperMock.Replay();
var controller = new AccountController
{
Mapper = autoMapperMock,
UserManagementService = userManagementServiceMock
};
this.mockRepository.ReplayAll();
// Act
var result = (RedirectToRouteResult)controller.Register(invalidRegistrationViewModel);
// Assert
Assert.IsTrue((string)result.RouteValues["Action"] == "RegisterSuccess");
}
As you can see, I set up multiple expectations on my mock:
I expect AutoMapper to be called twice
I expect UserManagementService to be called once
At the end of the test I have a single assertion that checks whether user was re-directed to the correct route.
So where do I check my assertions? I create another method that makes sure that my expectations have been met:
[TestCleanup]
public void Cleanup()
{
try
{
this.mockRepository.VerifyAll();
}
finally
{
}
}
So you are right, I have three assertions instead of one, but I structure my code in such a way so it appears that I have only one assertion.
I would recomend moving all of the "Arrange" and "Act" code into a Setup() method, and split the rest into three tests. This will make each individual test much easier to read, and let you give each test a name that corresponds better to the actual assert it contains.
private TemplateViewModel _templateViewModel;
private ITemplateDataProvider _mock2;
private IMappingEngine _mock2;
private TemplateController _controller;
private ActionResult _result;
[Setup]
public void Setup(){
// ARRANGE
_templateViewModel = new TemplateViewModel { Name = "MyTest" };
_mock1 = new Mock<ITemplateDataProvider>();
_mock2 = new Mock<IMappingEngine>();
_controller = new TemplateController(_mock1.Object, _mock2.Object);
_mock1.Setup(m => m.TemplateExists("MyTest")).Returns(true);
// Set ModelState.IsValid to false
_controller.ModelState.AddModelError("Name",
"This name already exists.");
_result = controller.Create(_templateViewModel);
}
[Test]
public void Create_TemplateAlreadyExists_ModelStateIsInvalid()
{
Assert.IsFalse(_controller.ModelState.IsValid);
}
[Test]
public void Create_TemplateAlreadyExists_ResultIsPartialViewResult()
{
Assert.IsInstanceOfType(typeof(PartialViewResult), _result);
}
[Test]
public void Create_TemplateAlreadyExists_ResultModelMatchesTemplateModel()
{
Assert.AreEqual(_templateViewModel, ((PartialViewResult)_result).Model);
}

Mocking a simple service bus in ASP.NET MVC

I have a simple 'Service' system set up with an interface as shown below. I am trying to mock it for use in my unit testing, but am having a bit of an obstacle. The way it works is that I design classes that implement IRequestFor<T,R> and I would call the service bus like this...
var member = new Member { Name = "valid#email.com", Password = "validPassword" };
ServiceBus.Query<ValidateUser>().With(member);
This works fine in my code. I have no issues with it. But when I try to mock it, like this ..
var service = Mock.Create<IServiceBus>();
// Model
var model = new Web.Models.Membership.Login
{
Email = "acceptible#email.com",
Password = "acceptiblePassword",
RememberMe = true
};
// Arrange
Mock.Arrange(() => service.Query<Membership.Messages.ValidateMember>().With(model))
.Returns(true);
I am given the following error.
NullReferenceException
I don't even know what the exception is on. It 'points' to the ServiceBus in my Controller code, and if I use the debugger, the object is like .. {IServiceBus_Proxy_2718486e043f432da4b143c257cef8ce}, but other than that, everything else looks the exact same as if I step through it in a normal run.
I am using Telerik JustMock for the mocking, but I don't know how I would do this in a different mocking framework either. I am using Ninject for my Dependency Injection, as well. Can anyone help me?
For convenience, I have included as much of my code as possible below.
Code Reference
Service Bus
public interface IServiceBus
{
T Query<T>() where T : IRequest;
T Dispatch<T>() where T : IDispatch;
}
public interface IRequest
{
}
public interface IDispatch
{
}
public interface IRequestFor<TResult> : IRequest
{
TResult Reply();
}
public interface IRequestFor<TParameters, TResult> : IRequest
{
TResult With(TParameters parameters);
}
public interface IDispatchFor<TParameters> : IDispatch
{
void Using(TParameters parameters);
}
Service Bus Implementation
public class ServiceBus : IServiceBus
{
private readonly IKernel kernel;
public ServiceBus(IKernel kernel) {
this.kernel = kernel;
}
/// <summary>
/// Request a query behavior that may be given parameters to yield a result.
/// </summary>
/// <typeparam name="T">The type of query to request.</typeparam>
/// <returns></returns>
public T Query<T>() where T : IRequest
{
// return a simple injected instance of the query.
return kernel.Get<T>();
}
/// <summary>
/// Request a dispatch handler for a given query that may be given parameters to send.
/// </summary>
/// <typeparam name="T">The type of handler to dispatch.</typeparam>
/// <returns></returns>
public T Dispatch<T>() where T : IDispatch
{
// return a simple injected instance of the dispatcher.
return kernel.Get<T>();
}
}
Service Bus Dependency Injection Wiring (Ninject)
Bind<IServiceBus>()
.To<ServiceBus>()
.InSingletonScope();
Complete Unit Test
[TestMethod]
public void Login_Post_ReturnsRedirectOnSuccess()
{
// Inject
var service = Mock.Create<IServiceBus>();
var authenticationService = Mock.Create<System.Web.Security.IFormsAuthenticationService>();
// Arrange
var controller = new Web.Controllers.MembershipController(
service, authenticationService
);
var httpContext = Mock.Create<HttpContextBase>();
// Arrange
var requestContext = new RequestContext(
new MockHttpContext(),
new RouteData());
controller.Url = new UrlHelper(
requestContext
);
// Model
var model = new Web.Models.Membership.Login
{
Email = "acceptible#email.com",
Password = "acceptiblePassword",
RememberMe = true
};
// Arrange
Mock.Arrange(() => service.Query<Membership.Messages.ValidateMember>().With(model))
.Returns(true);
// Act
var result = controller.Login(model, "/Home/");
// Assert
Assert.IsInstanceOfType(result, typeof(RedirectResult));
}
Actual Query Method
public class ValidateMember : IRequestFor<IValidateMemberParameters, bool>
{
private readonly ISession session;
public ValidateMember(ISession session) {
this.session = session;
}
public bool With(IValidateMemberParameters model)
{
if (String.IsNullOrEmpty(model.Email)) throw new ArgumentException("Value cannot be null or empty.", "email");
if (String.IsNullOrEmpty(model.Password)) throw new ArgumentException("Value cannot be null or empty.", "password");
// determine if the credentials entered can be matched in the database.
var member = session.Query<Member>()
.Where(context => context.Email == model.Email)
.Take(1).SingleOrDefault();
// if a member was discovered, verify their password credentials
if( member != null )
return System.Security.Cryptography.Hashing.VerifyHash(model.Password, "SHA512", member.Password);
// if we reached this point, the password could not be properly matched and there was an error.
return false;
}
}
Login Controller Action
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult Login(Web.Models.Membership.Login model, string returnUrl)
{
if (ModelState.IsValid)
{
// attempt to validate the user, and if successful, pass their credentials to the
// forms authentication provider.
if (Bus.Query<ValidateMember>().With(model))
{
// retrieve the authenticated member so that it can be passed on
// to the authentication service, and logging can occur with the
// login.
Authentication.SignIn(model.Email, model.RememberMe);
if (Url.IsLocalUrl(returnUrl))
return Redirect(returnUrl);
else
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Login View Model
public class Login : Membership.Messages.IValidateMemberParameters
{
[Required]
[DataType(DataType.EmailAddress)]
[RegularExpression(#"^[a-z0-9_\+-]+(\.[a-z0-9_\+-]+)*#(?:[a-z0-9-]+){1}(\.[a-z0-9-]+)*\.([a-z]{2,})$", ErrorMessage = "Invalid Email Address")]
[Display(Name = "Email Address")]
public string Email { get; set; }
[Required]
[StringLength(32, MinimumLength = 6)]
[DataType(DataType.Password)]
[RegularExpression(#"^([a-zA-Z0-9##$%]){6,32}$", ErrorMessage = "Invalid Password. Passwords must be between 6 and 32 characters, may contain any alphanumeric character and the symbols ##$% only.")]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
I don't have any real experience with how JustMock works in terms of recursive/nested mocking, but looking at the documentation it may look like that kind of mocking works only if your intermediate chain members are properties. And you're trying to implicitly mock IServiceBus method, which is generic, what can be an obstacle, too.
Mock.Arrange(() => service.Query<Membership.Messages.ValidateMember>().With(model))
.Returns(true);
You want to set the expectation here on With method from ValidateMember, assuming that the Query<T> method on IServiceBus will be mocked automatically, which may not be a case.
What should work here is to mock it more "traditionally", with two steps - first mock your Query<T> method on IServiceBus to return a mock of ValidateMember, which you should mock to return true.
var validateMemberMock = Mock.Create<Membership.Messages.ValidateMember>();
Mock.Arrange(() => service.Query<Membership.Messages.ValidateMember>())
.Returns(validateMemberMock);
Mock.Arrange(() => validateMemberMock.With(model))
.Returns(true);
EDIT
Here's my passing code doing more less the same what yours:
[TestClass]
public class JustMockTest
{
public interface IServiceBus
{
T Query<T>() where T : IRequest;
}
public interface IRequest
{
}
public interface IRequestFor<TParameters, TResult> : IRequest
{
TResult With(TParameters parameters);
}
public class ValidateMember : IRequestFor<IValidateMemberParameters, bool>
{
public bool With(IValidateMemberParameters model)
{
return false;
}
}
public class MembershipController
{
private IServiceBus _service;
public MembershipController(IServiceBus service)
{
_service = service;
}
public bool Login(Login model)
{
return _service.Query<ValidateMember>().With(model);
}
}
public interface IValidateMemberParameters
{
}
public class Login : IValidateMemberParameters
{
public string Email;
public string Password;
public bool RememberMe;
}
[TestMethod]
public void Login_Post_ReturnsRedirectOnSuccess()
{
// Inject
var service = Mock.Create<IServiceBus>();
// Arrange
var controller = new MembershipController(service);
// Model
var model = new Login
{
Email = "acceptible#email.com",
Password = "acceptiblePassword",
RememberMe = true
};
var validateMemberMock = Mock.Create<ValidateMember>();
Mock.Arrange(() => service.Query<ValidateMember>())
.Returns(validateMemberMock);
Mock.Arrange(() => validateMemberMock.With(model)).IgnoreArguments()
.Returns(true);
// Act
var result = controller.Login(model);
// Assert
Assert.IsTrue(result);
}
}

Get async callback value in unittest debug

I got UnitTest method which calls method with callback
[Test]
public void GetUserAsyncTest()
{
User result;
_restTest.GetUserAsync((user) =>
{
result = user;
});
Assert.AreEqual("xy", result.Email);
}
This is my method signature
/// <summary>
/// Retrieve the User details for the currently authenticated User
/// </summary>
/// <param name="callback">Method to call upon successful completion</param>
public void GetUserAsync(Action<User> callback)
How can I test this and get value from callback? Currently my result is always null which is logical.
Use an event to wait until the async method has finished:
[Test]
public void GetUserAsyncTest()
{
//Action<User> user = null;
User result;
ManualResetEvent waitEvent = new ManualResetEvent(false);
_restTest.GetUserAsync((user) =>
{
result = user;
waitEvent.Set();
});
waitEvent.WaitOne();
Assert.AreEqual("xy", result.Email);
}
Also changed user.Email to result.Email. Suspected you want to check the result variable.

Categories