Visuals Studio 2012 unit testing set user.identity - c#

Using C# I'm trying to unit test controller actions and time how long it takes for them to return. I'm using the unit testing framework built into VS2012 Ultimate.
Unfortunately I'm also trying to wrap my head around TestContext and how to use it..
Some example code (my controller action):
[HttpPost]
public JsonResult GetUserListFromWebService()
{
JsonResult jsonResult = new JsonResult();
WebService svc = new WebService();
jsonResult.Data = svc.GetUserList(User.Identity.Name);
return jsonResult;
}
When I try to unit test this, User.Identity.Name is null so it throws an exception. My current unit test code looks like:
[TestClass]
public class ControllerAndRepositoryActionTests {
public TestContext testContext { get; set; }
private static Repository _repository;
private username = "domain\\foobar";
private static bool active = true;
[ClassInitialize]
public static void MyClassInitialize(TestContext testContext)
{
_repository = new WebServiceRepository();
}
#region Controller method tests
[TestMethod]
public void GetUserListReturnsData()
{
Controller controller = new Controller();
var result = controller.GetUserListFromWebService();
Assert.IsNotNull(result.Data);
}
#endregion
#region service repository calls - with timing
[TestMethod]
public void GetUserListTimed()
{
testContext.BeginTimer("Overall");
var results = _repository.GetUserList(username, active);
foreach (var result in results)
{
Console.WriteLine(result.UserID);
Console.WriteLine(result.UserName);
}
testContext.EndTimer("Overall");
}
#endregion
}
Can I use TestContext to set the User.Identity that will be eventually used in the GetUserListFromWebService call?
If I can, what is the accepted way to assign TestContext. When I get it as a param in MyClassInitialize do I set my member variable, or am I supposed to pass it as a param to the TestMethods in some way?
Am I completely missing the point and should I be using some other mocking framework?

To make this test to work, I should change the signature of your class. Because you can not make a stub or a mock of your class Webservice, because you are creating it in the method.
class YourClass
{
private readeonly WebService _ws;
public YourClass(WebService ws)
{
_ws=ws;
}
[HttpPost]
public JsonResult GetUserListFromWebService()
{
JsonResult jsonResult = new JsonResult();
jsonResult.Data = _ws.GetUserList(User.Identity.Name);
return jsonResult;
}
}
Now you can in your test easily mock the class WebService with Moq or other frameworks. To make it eaven easier you shoul create an interface to your class WebService that implements the method GetUserList();
And to mock the User.Identy
public SomeController CreateControllerForUser(string userName)
{
var mock = new Mock<ControllerContext>();
mock.SetupGet(p => p.HttpContext.User.Identity.Name).Returns(userName);
mock.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);
var controller = new SomeController();
controller.ControllerContext = mock.Object;
return controller;
}
Or read this blog post http://weblogs.asp.net/rashid/

Related

How to correctly mock mongoDb with XUnit in C#?

Problem:
I am new to writing unit testing in c# using xunit. So I am trying to mock the MongoDB connection. In my project I have use repository pattern there I have used unit of work class like this. so I am accessing every repository via it. so the unit of work class code is here.
namespace QuestionBank.API.Repositories
{
public class UnitOfWork : IUnitOfWork
{
public readonly IQuestionsBankDBContext _context;
private readonly ILogger<UnitOfWork> _logger;
private Dictionary<Type, object> repositories;
private IQuestionsRepository _questionsRepository;
private ICampaignQuestionsRepository _campaignQuestionsRepository;
private ICandidateAnswerRepository _candidateAnswerRepository;
private IIntergrationEventLogRepository _integrationEventLogRepository;
private IControlRepository _controlRepository;
public UnitOfWork(IQuestionsBankDBContext context, ILogger<UnitOfWork> logger)
{
_context = context;
_logger = logger;
}
public IQuestionsRepository QuestionsRepository
{
get
{
this._questionsRepository = new QuestionsRepository(_context as IQuestionsBankDBContext, this, _logger);
return this._questionsRepository;
}
}
public ICandidateAnswerRepository CandidateAnswerRepository
{
get
{
this._candidateAnswerRepository = new CandidateAnswerRepository(_context as IQuestionsBankDBContext, this, _logger);
return this._candidateAnswerRepository;
}
}
public ICampaignQuestionsRepository CampaignQuestionsRepository
{
get
{
this._campaignQuestionsRepository = new CampaignQuestionsRepository(_context as IQuestionsBankDBContext, this, _logger);
return this._campaignQuestionsRepository;
}
}
public IIntergrationEventLogRepository IntegrationEventLogRepository
{
get
{
this._integrationEventLogRepository = new IntergrationEventLogRepository(_context as IQuestionsBankDBContext, this, _logger);
return this._integrationEventLogRepository;
}
}
public IControlRepository ControlRepository
{
get
{
this._controlRepository = new ControlRepository(_context as IQuestionsBankDBContext, this, _logger);
return this._controlRepository;
}
}
public IGenericRepository<TDocument> GetRepository<TDocument>() where TDocument : IDocument
{
if (this.repositories == null)
{
this.repositories = new Dictionary<Type, object>();
}
var type = typeof(TDocument);
if (!this.repositories.ContainsKey(type))
{
this.repositories[type] = new GenericRepository<TDocument>(_context);
}
return (IGenericRepository<TDocument>)this.repositories[type];
}
}
}
So in the unit test to mock services and repositories, I need to pass database context to unitofwork. I tried it this way.
var mockDbContext = new Mock<QuestionsBankDBContext>();
var dbContext = mockDbContext.Object;
var mock = new Mock<ILogger<UnitOfWork>>();
_logger = mock.Object;
unitOfWork = new UnitOfWork(dbContext, _logger);
questionsService = new QuestionsService(unitOfWork);
campaignQuestionsService = new CampaignQuestionsService(unitOfWork);
tokenService = new TokenService();
stringLocalizer = new Mock<IStringLocalizer<SharedResource>>();
questionBankIntergrationEventService = new Mock<IQuestionBankIntergrationEventService>();
questionsController = new QuestionsController(questionsService, campaignQuestionsService, stringLocalizer.Object, tokenService, questionBankIntergrationEventService.Object);
contextMock = new Mock<HttpContext>();
And this is my DB context class.
using MongoDB.Driver;
using QuestionBank.API.Models;
namespace QuestionBank.API.Data
{
public class QuestionsBankDBContext : IQuestionsBankDBContext
{
public IMongoClient Client { get; set; }
public IMongoDatabase Database { get; set; }
public QuestionsBankDBContext(IQuestionBankDatabaseSettings settings)
{
Client = new MongoClient(settings.ConnectionString);
Database = Client.GetDatabase(settings.DatabaseName);
}
}
}
Then I wrote a unit test like this.
[Theory]
[InlineData("61879e54e86be1fa5e41831f")]
[InlineData("61879e54e86be1fa5e41831e")]
public async Task GetQuestionById(string questionId)
{
var actionResult = await questionsController.GetQuestionById(questionId);
var result = actionResult as ObjectResult;
Assert.NotNull(result.Value);
if (result.StatusCode == (int)System.Net.HttpStatusCode.OK)
{
Assert.IsType<Questions>(result.Value);
}
else if (result.StatusCode == (int)System.Net.HttpStatusCode.NotFound)
{
Assert.Contains("ErrorCode", result.Value.ToString());
}
else if (result.StatusCode == (int)System.Net.HttpStatusCode.InternalServerError)
{
var code = (int)ErroCodes.InternalServerError;
Assert.Contains(code.ToString(), result.Value.ToString());
}
}
Then when running this it gives
And my question controller GetQuestionById is like this.
[HttpGet]
//[Authorize(Roles = "SuperAdmin,Admin")]
[Route("getquestionbyidfrombank")]
[ProducesResponseType(typeof(Questions), 200)]
[ProducesResponseType(typeof(string), 404)]
[ProducesResponseType(typeof(string), 500)]
public async Task<IActionResult> GetQuestionById([FromQuery] string questionId)
{
try
{
string errorText;
if (!string.IsNullOrEmpty(questionId))
{
var question = await
questionsService.GetQuestionById(questionId);
return Ok(question);
}
else
{
errorText = string.Format(stringLocalizer[Constants.ErrorCodeString],
(int)ErroCodes.SpecifiedItemNotFound,
stringLocalizer[Helper.ToEnumString(ErroCodes.SpecifiedItemNotFound)]);
return StatusCode(404, errorText);
}
}
catch (Exception ex)
{
string exceptionData =
$"Exception occured while getiing question by id. " +
$"\nException Data: Message- {ex.Message}; " +
$"InnerException- {ex.InnerException}; StackTrace- {ex.StackTrace}";
string errorText = string.Format(stringLocalizer[Constants.ErrorCodeString],
(int)ErroCodes.InternalServerError,
stringLocalizer[Helper.ToEnumString(ErroCodes.InternalServerError)]);
return StatusCode(500, errorText);
}
}
this is how I do the service instantiation.
public QuestionsService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
Get question by id function
public async Task<Questions> GetQuestionById(string id)
{
var question = await _unitOfWork.QuestionsRepository.FindByIdAsync(id);
return question;
}
Can someone help me to write this unit test correctly and solve this issue. I tried a lot to find out a way to do this but I could not able to do it. Thank you
Don't - just because something can be mocked, doesn't mean it should.
Instead, you can a docker image to run Mongo, drop and create a DB per test class init, drop collections per test init.
Testing a DAL (data-access-layer) without the DB is a waste of time and won't help you actually find bugs.
When you unit test your other components, mock the entire DAL to return the objects you expect.
And do not skip writing a test for your entire service that includes an empty/pre-populated-via-test-config-data DB.
Also, the fields in your DbContext should be private, not public and while passing a constant instance of a DbContext to MongoDB is OK, because MongoDB context is stateless (no transactions and connections are pooled), in general passing a DbContext via constructor is wrong (because relational DBs have transactions and the connections should not be kept open), instead pass a Func<DbContext> (e.g. public MyClass(Func<DbContext> contextConstructor)) which returns the constructor and have DbContext implement IDisposable. This way the client class can do using (context = contextCreator()) { ... }.
You should create a mock of the interface IQuestionsBankDBContext not the class QuestionsBankDBContext. Apart from that your test is not a unit test, it's more of an integration test because you are creating an instance of a controller and some services, and you mock only the database layer of your application. In unit tests you should test only a single layer. If you write unit tests for a controller then you should mock the services and their behavior (the direct dependencies of the controller).
Looking at your controller method, first unit test should check that when you pass not null and not empty question id then your method returns OkResult. For this test the mock of questionsService could return a question object.
Next test should check the opposite case, when it gets empty string it should return a response with code 404. (In my opinion it should be 400 but we are talking about unit tests)
Last test should check the exception handling. For example you pass a valid questionId in the test, but the mock of questionService throws an exception. In this test you can assert that the response has status code 500.
If you want to test many cases with one test method (a Theory in XUnit) then all these cases should have the same result, or you should provide an expected result with each case.

NUnit test of constructor fails because of missing parameter

I am trying to run a Unit Test using NUnit and have therefore followed a tutorial, which states the following:
[TestFixture]
public class TestFootballplayerController
{
[Test]
public void FootBallPlayer_CheckingIfControllerReturnsCorrectView_MustReturnTrue()
{
string expected = "CreatePlayer";
FootballplayerController controller = new FootballPlayerController();
var result = controller.CreateIngredient() as ViewResult;
Assert.AreEqual(expected, result.ViewName);
}
}
The tutorial assumes I have a empty default constructor, but my constructor contains a parameter with my DBContext as follows:
public class FootballplayerController : Controller
{
private readonly FootballContext _context;
public FootballplayerController(FootballContext context)
{
_context = context;
}
public IActionResult CreatePlayer()
{
return View();
}
}
Visual Studio suggests that I create an empty constructor, but in that way I think I will just test something, that shouldn't be tested, instead of the correct constructor with the parameter.
If the answer is obvious, then I must say, I am new to unit testing, and can't work a way around this. Do I have to fake a parameter?
In this case, you can just mock this class using e.g MoQ framework
[Test]
public void FootBallPlayer_CheckingIfControllerReturnsCorrectView_MustReturnTrue()
{
string expected = "CreatePlayer";
var mock = new Mock<FootballContext>();
FootballplayerController controller = new FootballPlayerController(mock.Object);
var result = controller.CreateIngredient() as ViewResult;
Assert.AreEqual(expected, result.ViewName);
}
but you must remember that now is just empty class in this test. You can create better mock, by mocking all your DbSets, and make them IQueryable.

Mock httpcontext.current.request.files

I am implementing nUnit Test case for one of my method called, UploadFile(), some thing like below
public void UploadFile(string siteId, string sitePageId)
{
int fileCount = HttpContext.Current.Request.Files.Count;
//Rest of code
}
so basically i am reading file using HttpContext.Current.Request.Files.
From UI it is working fine but when i am implementing nUnit test case for it, i am not able to mock HttpContext.Current.Request.Files. I googled about some of mocking tools but there also i didn't get anything related to mocking of HttpContext.Current.Request.Files. Please help me how to mock it or write test case for my method.
You could use dependency injection and then inject an instance of HttpContextBase into the class. Supposing you're using MVC:
public class MyController : Controller
{
HttpContextBase _context;
public MyController(HttpContextBase context)
{
_context = context
}
public void UploadFile(string siteId, string sitePageId)
{
int fileCount = _context.Request.Files.Count;
//Rest of code
}
}
Now you can instantiate the controller with a mock of HttpContextBase. This is how you would do it with Moq:
[Test]
public void File_upload_test()
{
var contextmock = new Mock<HttpContextBase>();
// Set up the mock here
var mycontroller = new MyController(contextmock.Object);
// test here
}

Mocked Object Still Making Calls to Service

So I'm writing tests for our MVC4 application and I'm testing Controller actions specifically. As I mention in the title, the test still hits the service (WCF) instead of returning test data. I have this controller:
public class FormController : Controller
{
public SurveyServiceClient Service { get; set; }
public SurveyDao Dao { get; set; }
public FormController(SurveyServiceClient service = null, SurveyDao dao = null)
{
this.Service = service ?? new SurveyServiceClient();
this.Dao = dao ?? new SurveyDao(Service);
}
//
// GET: /Form/
public ActionResult Index()
{
var formsList = new List<FormDataTransformContainer>();
Dao.GetForms().ForEach(form => formsList.Add(form.ToContainer()));
var model = new IndexViewModel(){forms = formsList};
return View("Index", model);
}
And it uses this DAO object:
public class SurveyDao
{
private readonly SurveyServiceClient _service;
private readonly string _authKey;
public SurveyDao(SurveyServiceClient serviceClient)
{
_service = serviceClient;
}
....
public FormContract[] GetForms()
{
var forms = _service.RetrieveAllForms();
return forms;
}
And this is my test using JustMock, the mock on GetForms() returns some test data in a helper class:
[TestClass]
public class FormControllerTest
{
private SurveyDao mockDao;
private SurveyServiceClient mockClient;
public FormControllerTest()
{
mockClient = Mock.Create<SurveyServiceClient>();
mockDao = Mock.Create<SurveyDao>(mockClient);
}
[TestMethod]
public void TestIndexAction()
{
//Arrange
var controller = new FormController(mockClient, mockDao);
Mock.Arrange(() => mockDao.GetForms()).Returns(TestHelpers.FormContractArrayHelper);
//Act
var result = controller.Index() as ViewResult;
//Assert
Assert.IsInstanceOfType(result.Model, typeof(IndexViewModel));
}
}
My problem is that when I run the test, the Service is still being called. I've verified this using Fiddler as well as debugging the test and inspecting the value of "result" which is populated with our service's test data.
EDIT:
I've changed the test constructor to be a [TestInitialize] function, so the Test now looks like this:
[TestClass]
public class FormControllerTest
{
private SurveyDao mockDao;
private SurveyServiceClient mockClient;
[TestInitialize]
public void Initialize()
{
mockClient = Mock.Create<SurveyServiceClient>();
mockDao = Mock.Create<SurveyDao>(Behavior.Strict);
}
[TestMethod]
public void TestIndexAction()
{
//Arrange
var controller = new FormController(mockClient, mockDao);
Mock.Arrange(() => mockDao.GetForms()).Returns(TestHelpers.FormContractArrayHelper);
//Act
var result = controller.Index() as ViewResult;
//Assert
Assert.IsInstanceOfType(result.Model, typeof(IndexViewModel));
}
}
Please verify that you are using the correct assembly for JustMock. There are a few different ones (VisualBasic, Silverlight, JustMock). The JustMock one is the one you should be including in your project.
Failure to include the correct one will cause the behavior that you are describing (method not being properly stubbed).
The JustMock manual explains (highlights by me):
By default Telerik JustMock uses loose mocks and allows you to call
any method on a given type. No matter whether the method call is
arranged or not you are able to call it.
You can control this behavior when calling the Create() method of you Mock:
var foo = Mock.Create<IFoo>(Behavior.Strict);
There you can specify what the mock object should do if you have not explicitly implemented a certain method. In your case (I think it is the default behavior) the mock indeed calls the original method on the object that you want to mock.
You have the following choices in the Behavior Enumeration enumeration:
Loose: Specifies that by default mock calls will behave like a stub, unless explicitly setup.
RecursiveLoose: Specifies that by default mock calls will return mock objects, unless explicitly setup.
Strict: Specifies that any calls made on the mock will throw an exception if not explictly set.
CallOriginal: Specifies that by default all calls made on mock will invoke its corresponding original member unless some expecations are set.

Mocking static method options

I understand that you can't mock a static method with moq, but I was wondering what my possible options are
I have a controller class defined
public class CustomerController : BaseController
{
private ICustomerManager cm;
public CustomerController()
: this(new CustomerManager())
{
}
public CustomerController(ICustomerManager customerMan)
{
cm = customerMan;
}
public ActionResult EditContact(ContactVM model, IEnumerable<HttpPostedFileBase> Files, PageAction pageAction)
{
if (ModelState.IsValid)
{
InitializeContactVM(model); //throws an error
}
}
private void InitializeContactVM(ContactVM model)
{
model.Customer = cm.GetViewFindCustomerDetails((int)model.CustomerId);
model.ContactClassificationList = AddBlankToList(SelectLists.ContactClassifications(false));
model.ContactSourceList = AddBlankToList(SelectLists.ContactSources(false));
}
}
And my unit test looks like this:
public void Edit_Contact_Update_Existing_Contact()
{
var dataManager = new Mock<IReferenceDataManager>();
//dataManager.Setup(a=>a.GetContactClassifications()).Returns()
var contact = InitializeContact();
var contactvm = new ContactVM(contact);
var fileMock = new Mock<HttpPostedFileBase>();
var files = new[] {fileMock.Object};
var mocManager = InitializeMocManagerContact();
mocManager.Setup(a => a.GetContactById(It.IsAny<int>())).Returns(contact);
mocManager.Setup(a => a.UpdateContact(It.IsAny<ContactVM>(), It.IsAny<string>())).Returns(contact);
var controller = new CustomerController(mocManager.Object);
var controllerContext = InitializeContext();
controller.ControllerContext = controllerContext.Object;
// mocManager.CallBase = true;
var result = controller.EditContact(contactvm, files, PageAction.Default) as ViewResult;
var model = result.ViewData.Model as ContactVM;
Assert.IsTrue(model.ContactId == contact.CONTACT_ID);
}
The problem is in the private method where it calls SelectLists.ContactClassifications(false), it then tries to hit the database.
The SelectList class is defined like
public static class SelectLists
{
private static readonly ReferenceDataManager _dataManager = new ReferenceDataManager();
public static SelectList ContactClassifications(bool includeDeleted)
{
var data = _dataManager.GetContactClassifications();
}
}
and it is the line where it calls GetContactClassifications in the SelectList that it feels like I should be able to mock (if the method that calls it can't be mocked because it is static). This one does implement an interface.
Even if there is some way that the private method in the Controller (InitialiseContactVM) could be mocked it would suit me.
Is there any way to achieve any of these things?
Ideally, your DAL should not be made out of static methods, but normal objects that provide services injected though an interface into controllers or whatever needs it.
But if you can't/don't want to change it, you the "standard" way to let you mock it would be to decouple the static method call from your controller. It can be done by wrapping it in a class that contains the static call and implements an interface, that is injected in the controller, and therefore mocked out in the tests. It's somewhat similar to testing a MessageBox call or the current system date/time.
First create an interface that will contain your static method calls:
public interface ISelectListsWrapper
{
SelectList ContactClassifications(bool includeDeleted);
}
Then a class will implement it by calling the actual static method:
public class SelectListsWrapper : ISelectListsWrapper
{
public SelectList ContactClassifications(bool includeDeleted)
{
return SelectLists.ContactClassifications(includeDeleted);
}
}
In the controller, you take an instance of this class in the constructor, save it to a local variable, and use that to call the static method though the wrapper:
private readonly ISelectListsWrapper selectLists;
public CustomerController(ICustomerManager customerMan, ISelectListsWrapper selectLists)
{
cm = customerMan;
this.selectLists = selectLists;
}
private void InitializeContactVM(ContactVM model)
{
model.Customer = cm.GetViewFindCustomerDetails((int)model.CustomerId);
model.ContactClassificationList = AddBlankToList(this.selectLists.ContactClassifications(false));
model.ContactSourceList = AddBlankToList(this.selectLists.ContactSources(false));
}
Finally, in the test, you just pass a mock of the wrapper and setup it to return whatever makes sense to that test.
The SelectLists class should be refactored to allow you to inject an IReferenceDataManager rather than instantiating one itself.

Categories