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