First Unit Tests! ASP.NET MVC with Repositories causing errors - unit-testing

I am very new to Unit Testing, so I am starting on my first set of tests today. I am using the Library JustMock from Telerik. Though any unit testing information is good. I am having a bit of trouble with an interface service that passes through my method. Below is my MembershipController.Register(model) method...
[CaptchaValidator]
[HttpPost]
public ActionResult Register(Models.Membership.Registration model)
{
// just for good mesure, truncate any spaces that are given
System.Text.RegularExpressions.Regex.Replace(model.Email, #"\s", "");
if (ModelState.IsValid)
{
// Attempt to register the User and return any applicable status that has to do
// with the result.
var createStatus = membershipService.RegisterMember(model.Email, model.Password);
// if the member is able to be created successfully, log them in now and begin the
// authentication portion of the registration, otherwise, display the registration
// errors and return to the view.
if (createStatus == Membership.MemberCreateStatus.Success)
{
formsAuthentication.SignIn(model.Email, false /* createPersistentCookie */);
return RedirectToAction("Success");
}
else
{
ModelState.AddModelError("", Membership.Validator.ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
And here is the paltry test I am trying to run...
[TestMethod]
public void Register_Post_ReturnsRedirectOnSuccess()
{
// Arrange
var controller = Mock.Create<Web.Controllers.MembershipController>();
var repository = Mock.Create<Membership.IMembershipService>();
Mock.Arrange(() => repository.RegisterMember("acceptible#email.com", "acceptiblePassword")).Returns(Membership.MemberCreateStatus.Success);
// Model
var model = new Web.Models.Membership.Registration
{
Email = "acceptible#email.com",
Password = "acceptiblePassword",
ConfirmPassword = "acceptiblePassword"
};
// Act
var result = controller.Register(model);
// Assert
Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
}
The test fails because membershipService is resolving as null. I'm not sure what to do here. This is my first forray into the Unit Testing aspect of ASP.NET MVC. Can anyone give me some advice?
I am using Ninject to inject IMembershipService through the Constructor. It is implemented by the class MembershipService. The code runs fine when I run it, but the unit tests fail.

I don't see you passing repository anywhere into your controller. Normally you would have IMembershipService as a parameter in your controller's constructor that you can then pass in when needed or use MVC's Service Locator to grab the Ninject instance and pass it in.
:)

Related

How to Unit Test a Method in Sitecore MVC having tightly coupled Dependency on two distinct Sitecore Contexts?

I have to unfortunately write Unit Tests for a legacy Sitecore MVC code base where two distinct Sitecore Contexts are called. I understand this comes under Integration Testing but i don't have the option of educating my project Leads on that front. So i have chosen to use FakeDb for emulating Sitecore Instance and NSubstitute for substituting injected Dependencies (can't use any Profilier API Frameworks like MS Fakes, TypeMock etc because of Budget constraints). I am providing the code below:
Method to be UnitTested
public bool DubiousMethod()
{
// This HttpContext call is pain area 1. This gets resolved when i call it using ItemContextSwitcher in Unit Tests.
string currentUrl = HttpContext.Current.Request.RawUrl;
// This Sitecore Context call to Site Name is pain area 2. This gets resolved when Unit Tests are run under SiteContextSwitcher.
string siteName = Sitecore.Context.Site.Name;
return true/False;
}
Unit Test Method
[Fact]
public void DubiousMethodUT()
{
// create a fake site context
var fakeSite = new Sitecore.FakeDb.Sites.FakeSiteContext(
new Sitecore.Collections.StringDictionary
{
{ "name", "website" }, { "database", "web" }, { "rootPath", "/sitecore/content/home" },
{ "contentStartItem", "home"}, {"hostName","https://www.myorignalsiteurl.com"}
});
using (new Sitecore.Sites.SiteContextSwitcher(fakeSite))
{
//DubiousClassObject.DubiousMethod(home) // When Debugging after uncommenting this line i get correct value in **Sitecore.Context.Site.Name**
using (Sitecore.FakeDb.Db db = new Sitecore.FakeDb.Db
{
new Sitecore.FakeDb.DbItem("home") { { "Title", "Welcome!" } ,
new Sitecore.FakeDb.DbItem("blogs") }
})
{
Sitecore.Data.Items.Item home = db.GetItem("/sitecore/content/home");
//bool abc = confBlogUT.IsBlogItem(home);
using (new ContextItemSwitcher(home))
{
string siteName = Sitecore.Context.Site.Name;
var urlOptions = new Sitecore.Links.UrlOptions();
urlOptions.AlwaysIncludeServerUrl = true;
var pageUrl = Sitecore.Links.LinkManager.GetItemUrl(Sitecore.Context.Item, urlOptions);
HttpContext.Current = new HttpContext(new HttpRequest("", pageUrl.Substring(3), ""), new HttpResponse(new StringWriter()));
Assert.False(DubiousClassObject.DubiousMethod(home); //When Debugging after commenting above DubiousMethodCall i get correct value for **HttpContext.Current.Request.RawUrl**
}
}
}
}
As you can observe that when i try to call the method from FakSiteContext then i am getting the correct value for Sitecore.Context.Site.Name however my code breaks when HttpContext.Current.Request.RawUrl is invoked in the method. Opposite happens when i invoke the method from ContextItemSwitcher(FakeItem) context. So far i have not been able to find a way to merge both the Contexts (which i believe is impossible in Sitecore). Can anyone suggest if i run my Unit Tests in an overarching context where i am able to contrl fakeSite Variables as well as FakeItem context variables as well and by extensions any other Sitecore Context calls?
Any help would be appreciated.
I'd recommend to take a look at Unit testing in Sitecore article as it seem to be what you need.
In short - you'll need to do a few adjustments in your code to make it testable:
1) Replace static HttpContext with abstract HttpContextBase (impl. HttpContextWrapper) so that everything can be arranged - DubiousMethod gets an overload that accepts DubiousMethod(HttpContextBase httpContext).
2) As for Sitecore Context data - it has Sitecore.Caching.ItemsContext-bound semantics (as mentioned in the article), so you could cleanup the collection before/after each test to get a sort of isolation between tests.
Alternatively you could bake a similar wrapper for Sitecore.Context as ASP.NET team had done for HttpContext -> HttpContextBase & impl HttpContextWrapper.

Unit testing not using correct mocking class

I am using Rhino.Mocks and Structure map to help unit test my code. I have several tests that pass when they are ran by themselves, but when ran as a group fail to pass. The setup code for these unit tests is:
[TestInitialize()]
public void Setup()
{
ObjectFactory.Initialize(x =>
{
x.For(IManager)().Use(Handler)();
});
}
In my tests, I stub out this interface and call the method.
[TestMethod]
public void AreMultiple_Test()
{
var mackIManager = MockRepository.GenerateMock<IManager>();
mackIManager.Stub(u => u.GetTwoUserName(Arg<int>.Is.Anything)).Return(null);
ObjectFactory.Inject(typeof(IManager), mackIManager);
StepAdditionalActionBase actionBase = new StepAdditionalActionBase();
bool areMultiple = actionBase.AreMultiple(new WorkOrder { Id = "123" });
Assert.IsFalse(areMultiple);
}
Test Method 2
[TestMethod]
public void AreMultiple_Test()
{
var mackIManager = MockRepository.GenerateMock<IManager>();
mackIManager.Stub(u => u.GetTwoUserName(Arg<int>.Is.Anything)).Return("123");
ObjectFactory.Inject(typeof(IManager), mackIManager);
StepAdditionalActionBase actionBase = new StepAdditionalActionBase();
bool areMultiple = actionBase.AreMultiple(new WorkOrder { Id = "123" });
Assert.IsTrue(areMultiple);
}
This is unit testing the following code.
public bool AreMultiple(WorkOrder workOrder)
{
string secondUser = _handler.GetTwoUserName(_workflowManager.GetNumberForProject(workOrder.Id));
if (String.IsNullOrEmpty(secondUser ))
{
return false;
}
return true;
}
When I run them by themselves, they work fine. When I run them together, the first passes and the second fails. When I debug the second one, I find that that the return value in the Stubbed method is still coming back as null. How do I get this to use the new Stubbed method.
UPDATE.
I am using StructureMap as my container. From what I have been able to find, the following code is what is used to dispose of the container I got it from this link. When I added this, the test still fail when ran together, but pass when ran individually.
[TestCleanup()]
public void TestCLeanup()
{
ObjectFactory.Container.Dispose();
}
The tests work one by one but fails if run all together. The problem should be in the common part which is being shared across the tests making them dependent from each other. In this particular case that is static ObjectFactory which is nothing else but a Service Locator (anti-pattern).
In the tests, you mock the IManager interface and register it in the ObjectFactory:
ObjectFactory.Inject(typeof(IManager), mackIManager);
Then the SUT uses the ObjectFactory service locator to resolve and use the mocked interface (_handler field):
string secondUser = _handler.GetTwoUserName(...)
I suspect the first test registers the _handler and never clean it up properly, so that the same instance appears in the second test. You should reset the ObjectFactory between tests following the Register Resolve Release pattern.
Another (preferable) option is to refactor your SUT to receive the IManager handler dependency explicitly via constructor. That would simplify both SUT and tests moving the ObjectFactory configuration to the Composition Root.

Moq out parameters

I'm fairly new to using Moq and Nunit for unit testing and I'm having issues with one scenario. What I want is for my mock to have an out parameters which my system under test will then use to decide what action to take.
My system under test is an MVC API controller and in particular I'm trying to test the POST method. I want to return an error message for the object when validation fails.
Here is the method code for the controller:
public IHttpActionResult Post(Candidate candidate)
{
try
{
if(candidate==null)
return BadRequest();
IEnumerable<string> errors;
_candidateManager.InsertCandidate(candidate, out errors);
if (errors!=null && errors.Any())
return BadRequest(CreateErrorMessage("Invalid candidate: ", errors));
return CreatedAtRoute("DefaultApi", new {id = candidate.CandidateId}, candidate);
}
catch (Exception)
{
return InternalServerError();
}
}
This is my Unit Test Code:
[Test]
[Category("CandidateManagerController Unit Tests")]
public void Should_Return_Bad_Request_When_Creating_Invalid_Candidate()
{
IEnumerable<string> errors = new List<string>() {"error1", "error2"};
var mockManager = new Mock<ICandidateManager>();
mockManager.Setup(x => x.InsertCandidate(new Candidate(), out errors)).Callback(()=>GetErrors(errors));
var sut = new CandidateManagerController(mockManager.Object);
var actionResult = sut.Post(new Candidate());
Assert.IsInstanceOf<BadRequestResult>(actionResult);
}
What I expect is that when _candidateManager.InsertCandidate() is run then the errors variable is populated. However what is happening is that when you step through the controller code errors is null after _candidateManager.InsertCandidate() method is run.
If anyone has any ideas what I'm doing wrong or if what I want to do is not possible using Moq then please let me know.
Thanks
What you want to do is possible. If you look at the Quickstart docs at https://github.com/Moq/moq4/wiki/Quickstart, there is a section where it shows how you do setups for methods using out params. I have made two corrections to your code and it works.
You have to use the same candidate instance for both the mock setup and when you exercise the sut. Otherwise, Moq thinks that the two objects are different and your test setup becomes useless.
You don't have to use Callback in order to set the errors returned by the mocked CandidateManager.
Below is your test method with my changes.
[Test]
[Category("CandidateManagerController Unit Tests")]
public void Should_Return_Bad_Request_When_Creating_Invalid_Candidate()
{
IEnumerable<string> errors = new List<string>() {"error1", "error2"};
//instance to be used for both setup and test later
var candidate = new Candidate();
var mockManager = new Mock<ICandidateManager>();
//removed Callback
mockManager.Setup(x => x.InsertCandidate(candidate, out errors));
var sut = new CandidateManagerController(mockManager.Object);
var actionResult = sut.Post(candidate);
Assert.IsInstanceOf<BadRequestResult>(actionResult);
}
You have to make sure that when you call your SUT that you use the same instance passed to the out argument otherwise the call will fail.
In your example, the method under test passes a null instance into the mocked method thus negating the setup of the test.
If however you are not able to supply the same instances for the out then it doesn't look like you will be able to get a mock to pass successfully. Take a look a the Quick Start for Moq to get an understanding of it capabilities.

Grails unit test using grailsApplication

I have a controller that on the save method calls a thread to retrieve some files. The thread has start() in a domain that has this line-
RetrievalThread retrievalThread = grailsApplication.mainContext.getBean ('retrievalThread').
In my unit test I tried this and it worked(I'll keep the other lines omitted that have no bearing right now). Without this line an error occurs saying can't get mainContext on null object,talking about grailsApplication. .
Def mainContext = Mock(ApplicationContext)
MainContext.getBean(_) >>{ name ->
return new MockRetrievalThread()}
The mock thread doesn't do anything.
This test runs fine but, any test after this fail with a null pointer exception with no real information. Looks like a bunch of background grails stuff. Is there a way to clean this up or use something better than what I'm using?
I'm sure there's a way to clean this up in a tearDown, but I think there is a better way.
1.) I would use DI rather than going through grailsApplication.mainContext.getBean; is there a reason you are doing it this way?
class MyController {
def retrievalThread
getFiles() {
return [files: retrievalThread.getFiles(params.id)]
}
}
2.a.) Using DI, you can then just set the controller's retrievalThread to a new instance of MockRetrievalThread within your test.
void "test getFiles"() {
given:
controller.retrievalThread = new MockRetrievalThread()
when:
params.id = 1
def returnedFiles = controller.getFiles()
then:
// assertions
}
2.b.) Or skip the MockRetrievalThread altogether and mock the retrievalThread bean using the mockFor method, and then set the mocked version to the injected instance in your controller.
void "test getFiles"() {
given:
def retrievalThreadMock = mockFor(RetrievalThread)
retrievalThreadMock.demand.getFiles { Integer input ->
return ['file1', 'file2', 'etc.']
}
controller.retrievalThread = retrievalThreadMock.createMock()
when:
params.id = 1
def returnedFiles = controller.getFiles()
then:
// assertions
}
You can use integration testing instead to run the entire app, in order to avoid any beans not being injected.
grails create-integration-test org.bookstore.Book

Grails: How do you unit test a command object with a service injected into it

I am trying to test a Controller
that has a Command object with data binding.
The Command Object has a Service injected into it.
But When I try test the command object the injected service method
is never found as it is never "injected"
Is there a way to mock a service inside a command object?
Test method
void testLoginPasswordInvalid() {
mockRequest.method = 'POST'
mockDomain(User, [new User(login:"freddy", password:"realpassword")])
mockLogging(UserService) // userService mocked
MockUtils.prepareForConstraintsTests(LoginCommand)
def userService = new UserService()
def user = userService.getUser("freddy")//Gets called and returns the mockDomain
assert userService.getUser("freddy")//Passes
def cmd = new LoginCommand(login:"freddy", password:"letmein")
cmd.validate() // Fails (userService is nevr injected)
controller.login(cmd)
assertTrue cmd.hasErrors()
assertEquals "user.password.invalid", cmd.errors.password
assertEquals "/store/index", renderArgs.view
}
The getUser() method of the userService isn't found
Cannot invoke method getUser() on null object
java.lang.NullPointerException: Cannot invoke method getUser() on null object
Code
The login method of the controller being called,
def login = { LoginCommand cmd ->
if(request.method == 'POST') {
if(!cmd.hasErrors()){
session.user = cmd.getUser()
redirect(controller:'store')
}
else{
render(view:'/store/index', model:[loginCmd:cmd])
}
}else{
render(view:'/store/index')
}
}
The Command Object has a "userService" injected into it.
The validator calls this userService to find a user
class LoginCommand {
def userService
String login
String password
static constraints = {
login blank:false, validator:{ val, cmd ->
if(!cmd.userService.getUser()){
return "user.not.found"
}
}
}
The userService.getUser() looks like this.
class UserService {
boolean transactional = true
User getUser(String login) {
return User.findByLogin(login)
}
}
Service injection is done using Spring autowire-by-name. (Grep the Grails source tree for autowire to find a nice code fragment you can use to get it to autowire your controllers for you in integration tests.) This only functions in integration tests, where there's a Spring application context around that has the beans that can be injected.
In unit tests, you have to do this yourself since there's no Spring-land surrounding your stuff. This can be a pain, but gives you some benefits:
1) It's easy to inject mock versions of services - for example, using an Expando - in order to more closely specify the behavior of your controller's collaborating services, and to allow you to test only the controller logic rather than the controller and service together. (You can certainly do the latter in a unit test as well, but you have the choice of how to wire it up.)
2) It forces you to be explicit about the dependencies of your controller - if you depend on it, your tests will show it. This makes them a better specification for the behavior of your controller.
3) You can mock only the pieces of external collaborators your controller depends on. This helps your tests be less fragile - less likely to need to change when things change.
Short answer: your test method needs a cmd.userService = userService line.
What John says is on the mark. One example might be:
def mockUsers = [new User(login:"freddy", password:"realpassword")]
mockDomain(User, mockUsers)
def userService = [getUser:{String login -> mockUsers[0]}] as UserService
def cmd = new LoginCommand (/*arguments*/)
cmd.userService = userService
You can lookup other ways to mock objects at http://groovy.codehaus.org/Groovy+Mocks