Mocking a Simple Service Bus in ASP.NET MVC

I have a simple "Service" system configured with an interface as shown below. I am trying to make fun of it for use in my unit testing, but I have a bit of an obstacle. How it works, I design classes that implement IRequestFor<T,R> , and I would call the service bus as follows:

var member = new Member { Name = " valid@email.com ", Password = "validPassword" }; ServiceBus.Query<ValidateUser>().With(member);

This works fine in my code. I have no problem with this. But when I try to mock it, like that ..

 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 an exception is. It points to a ServiceBus in my controller code, and if I use a debugger, the object is similar to {IServiceBus_Proxy_2718486e043f432da4b143c257cef8ce} , but apart from that, everything else looks exactly as if I were going through it in normal mode,

I use Telerik JustMock for ridicule, but I don’t know how to do it in another mocking structure. I use Ninject for my dependency injection. Can anybody help me?

For convenience, I have included as much of my code as possible.

Code Link

Service tire

 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>(); } } 

Connection to commissioning service bus (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 Request 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; } } 

Input 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 to the model viewing system

 public class Login : Membership.Messages.IValidateMemberParameters { [Required] [DataType(DataType.EmailAddress)] [RegularExpression(@"^[a-z0-9_\+-]+(\.[a-z0-9_\+-]+)*@(?:[a-z0-9-]+){1}(\.[a-z0-9-]+)*\.([az]{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; } } 

enter image description here

+7
source share
1 answer

I have no real experience with JustMock in terms of recursive / nested mocking, but looking at the documentation , it might look like such tantalizing work only if your intermediate chain members are properties. And you are trying to implicitly mock the IServiceBus method, which is shared, which can be an obstacle too.

 Mock.Arrange(() => service.Query<Membership.Messages.ValidateMember>().With(model)) .Returns(true); 

You want to set the wait here on the With method from ValidateMember , assuming that the Query<T> method on IServiceBus will mock automatically, which may not be.

What you need to do here to do it more traditionally, with two steps - first mock your Query<T> method on IServiceBus to return a ValidateMember layout that you must 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, my transfer code does less than what you have:

 [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); } } 
+2
source

All Articles