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.
Related
I'm creating a solution that contains two projects: the web project ant it's test project. I'm using Log4net for logging purposes, CastleWindsor for dependency injection and moq for the tests.
The problem I have is the configuration of the test. I want to test the HomeController that is Logging to a file, but when I run the test I don't want to Log, I think is absurd.
Is there a way to skip Logging in the test project?
The HomeController class:
public class HomeController : Controller
{
// this is Castle.Core.Logging.ILogger, not log4net.Core.ILogger
public ILogger Logger { get; set; }
private IRowan _rowan;
public HomeController(IRowan rowan)
{
_rowan = rowan;
}
public ActionResult Index()
{
//In the [tests] Logger fails
Logger.Debug("GET Request traced");
Logger.Error("Example of Error");
String test = _rowan.DoSomething();
ViewBag.Title = test;
return View();
}
}
}
It's test:
[TestClass]
public class HomeControllerTest
{
private static WindsorContainer _container;
[ClassInitialize()]
public static void InstallWindsor()
{
_container = new WindsorContainer();
// configure other classes
}
[ClassCleanup()]
public static void DisposeContainer()
{
_container.Dispose();
}
[TestMethod]
public void Index()
{
// Disponer
var mock = new Mock<IRowan>();
mock.Setup(m => m.DoSomething()).Returns("Home Page");
HomeController controller = new HomeController(mock.Object);
// Actuar
ViewResult result = controller.Index() as ViewResult;
// Declarar
Assert.IsNotNull(result);
Assert.AreEqual("Home Page", result.ViewBag.Title);
}
}
If the answer is no, which is the best way to implement log4net for testing?
PD: When I run the code, It works fine. When I run the test, Logger throws an exception because is null.
PD: I'm starting using the Microsoft Technology.
You could mock your Logger and set it on your controller like so:
Mock<ILogger> mockLogger = new Mock<ILogger>();
controller.Logger = mockLogger.Object;
Note that you shouldn't really need to use CastleWindsor in your tests. That's useful for controlling the lifecycle of objects in your application but in your tests you should be injecting things by hand. You are actually doing this in the example above. From the code you've posted you can remove the ClassInitialize and ClassCleanup functions and it will run the same.
You can use an other config for your test project.
Read more: https://logging.apache.org/log4net/release/manual/configuration.html
I have a project created using Asp.Net Core, but I have a problem with unit testing one part of my controller's action, I use xUnit.net(2.2.0-beta2-build3300) for testing and Moq(4.6.25-alpha) for mocking, and FluentAssertions(4.13.0) and GenFu(1.1.1) to help me with my tests, I have a Unit of Work class (note that I cut it down to what's relevant to my question):
public class UnitOfWork : IUnitOfWork
{
private readonly WebForDbContext _context;
public UnitOfWork(WebForDbContext context)
{
_context = context;
}
private IContactRepository _contactRepository;
public IContactRepository ContactRepository
{
get
{
if (this._contactRepository == null)
{
this._contactRepository = new ContactRepository(_context);
}
return _contactRepository;
}
}
}
In my ContactRepository I have:
public class ContactRepository:IContactRepository
{
private WebForDbContext _context;
public ContactRepository(WebForDbContext context)
{
_context = context;
}
public Task<int> AddNewContactAsync(Contact contact)
{
_context.Contacts.Add(contact);
return _context.SaveChangesAsync();
}
}
I inject the Unit of Work to my controller, my action:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(ContactViewModel contactViewModel)
{
var contactWioutJavascript = _webForMapper.ContactViewModelToContact(contactViewModel);
int addContactResultWioutJavascript = await _uw.ContactRepository.AddNewContactAsync(contactWioutJavascript);
if (addContactResultWioutJavascript > 0)
{
return View("Success");
}
}
What I want to do is to stub my AddNewContactAsync method to return an integer bigger than 0 (10 in this case), to inter the if clause, and test to see if the correct view is returned, my test class:
public class ContactControllerTests
{
private Mock<IUnitOfWork> _uw;
private Mock<IWebForMapper> _webForMapper;
public ContactControllerTests()
{
_uw = new Mock<IUnitOfWork>();
_webForMapper = new Mock<IWebForMapper>();
}
[Fact]
public async Task Create_SouldReturnSuccessView_IfNewContactAdded()
{
var contactViewModel = A.New<ContactViewModel>();
_webForMapper.Setup(s => s.ContactViewModelToContact(contactViewModel)).Returns(A.New<Contact>());
_uw.Setup(u => u.ContactRepository.AddNewContactAsync(A.New<Contact>())).ReturnsAsync(10);
var sut = new ContactController(_uw.Object, _webForMapper.Object);
var result = (ViewResult)await sut.Create(contactViewModel);
result.ViewName.Should().Be("Success");
}
}
But the method AddNewContactAsync returns 0, and my test doesn't enter the if condition that leads to return View("Success"), I know that the problem doesn't have to do with ReturnAsync because I've used it with other async methods and it works, also _webForMapper is stubbed correctly and map the view model to my domain model and contactWioutJavascript is populated with value, but when I debug the test and reach the addContactResultWioutJavascript line, it returns 0, no matter what I do.
The things I did, but didn't work:
I mocked the ContactRepository, and tried to stub that instead:
_contactRepository.Setup(c => c.AddNewContactAsync(A.New<Contact>())).ReturnsAsync(10);
_uw.SetupGet<IContactRepository>(u => u.ContactRepository).Returns(_contactRepository.Object);
I also found other questions:
Moq Unit of Work
how to moq simple add function that uses Unit of Work and Repository Pattern
Mocking UnitOfWork with Moq and EF 4.1
But none of them helped, I'd appreciate any help.
You are almost there. Two things:
You do need to setup the ContactRepository property as Moq doesn't support "chaining" of setups.
Also, you need to use It.IsAny<>() instead of A.New<>():
_contactRepository.Setup(c => c.AddNewContactAsync(It.IsAny<Contact>())).ReturnsAsync(10);
This says "match any Contact that is passed in". When you used A.New<>(), you were saying "match the Contact instance that I just created with A.New<>(). In effect, that will never match anything since you didn't save or use the return value of A.New<>().
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
}
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.
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/