There is a method in my controller that returns attribute data from the current executing assembly into a partial view.
In this example, I'm merely pulling the Title, but I need to do more with it.
Controller:
var title = "";
var asm = Assembly.GetExecutingAssembly();
var attrs = asm.GetCustomAttributes(typeof(AssemblyTitleAttribute));
var titleAttr = (AssemblyTitleAttribute)attributes[0];
title = titleAttr.Title;
return PartialView("_Build", title);
When writing the unit test in Moq, I need to find a way to inject the Assembly attributes into a mock so that I can verify that the correct attributes are being generated when I run the controller test, and then do x or y with my asserts.
UnitTest:
//Arrange
//The magic I need to happen.
//Act
var controller = GetController();
var result = controller.MyMethod() as PartialViewResult;
var title = result.Model;
//Assert
Assert.AreEqual("Title", title); //currently static, need to verify against a mock
I know this is an extremely simple set of code, but I just need proof of concept at this point.
Is there a good way to create a fake Assembly?
Do I need to use System.Reflection.Emit?
You could create a virtual method e.g. GetCustomAttributes which provides the attributes for given type. Then in your test preject a testable class would derive from the controller class and override this method.
Home Controller:
private IDependency _someDependency;
public HomeController(IDependency someDependency)
{
_someDependency = someDependency;
}
public ActionResult MyMethod()
{
var title = "";
var version = "";
IEnumerable<Attribute> attributes = GetCustomAttributes(typeof(AssemblyVersionAttribute)).ToList();
AssemblyVersionAttribute verAttr = attributes.OfType<AssemblyVersionAttribute>().FirstOrDefault();
if (verAttr != null) version = verAttr.Version;
attributes = GetCustomAttributes(typeof(AssemblyTitleAttribute)).ToList();
AssemblyTitleAttribute titleAttr = attributes.OfType<AssemblyTitleAttribute>().FirstOrDefault();
if (titleAttr != null) title = titleAttr.Title;
return PartialView("_Build", title + version);
}
public virtual IEnumerable<Attribute> GetCustomAttributes(Type attributeType)
{
var asm = Assembly.GetExecutingAssembly();
var attrs = asm.GetCustomAttributes(attributeType);
return attrs;
}
Test:
[TestClass]
public class MyMethodTest
{
[TestMethod]
public void MyMethod_WhenCalled_PartialViewIsReturned()
{
// Arrange
// The magic I need to happen.
Mock<IDependency> dependencyStub = new Mock<IDependency>();
// dependencyStub.Setup(...).Returns(...);
var controller = new TestableHomeController(dependencyStub.Object)
{
UseFakeAttributes = true
};
// Act
var result = controller.MyMethod() as PartialViewResult;
// Assert
var model = result.Model;
Assert.AreEqual("MyFakeTitle1.0.0.0", model); // currently static, need to verify against a mock
}
private class TestableHomeController : HomeController
{
public bool UseFakeAttributes { get; set; }
public TestableHomeController(IDependency someDependency)
:base(someDependency)
{ }
public override IEnumerable<Attribute> GetCustomAttributes(Type attributeType)
{
return UseFakeAttributes
? new List<Attribute>
{
new AssemblyTitleAttribute("MyFakeTitle"),
new AssemblyVersionAttribute("1.0.0.0"),
new AssemblyDescriptionAttribute("Assembly fake description")
// next attributes ...
}.Where(a => a.GetType() == attributeType)
: base.GetCustomAttributes(attributeType);
}
}
}
Since this is static type information, you only need to evaluate it once per build. Consider populating a static collection (e.g. a dictionary) with this information at application start. At that point you can inject your dictionary into the controller, or you can modify your configuration to access the dictionary and inject only the values you need. In fact, provided this doesn't get out of control, it might be best to just have named string instances like "build" or "title" without even having to house them in a collection.
I wouldn't mess with the hassle of trying to get unit tests around parsing an assembly attribute unless the logic can be contained in a static method that your unit tests call directly. From a web app perspective, it's best to leave this type of stuff out of the controller; the bootstrapper layer is a much more appropriate location.
Related
I'm new to both unit tests, Autofac and mocks so likely, this is relatively easy, but I'm having a hard time figure it out.
I have this class SystemUnderTest with one dependency, and two methods GetValueOne and GetValueTwo.
public class SystemUnderTest : ISystemUnderTest
{
private readonly IDependency _dependency;
public SystemUnderTest(IDependency dependency)
{
_dependency = dependency;
}
public string GetValueOne()
{
return _dependency.GetValueOne();
}
public string GetValueTwo()
{
return _dependency.GetValueTwo();
}
}
public interface ISystemUnderTest
{
string GetValueOne();
string GetValueTwo();
}
These methods gets data from the dependency.
public class Dependency : IDependency
{
public string GetValueOne()
{
return "get-value-one";
}
public string GetValueTwo()
{
return "get-value-two";
}
}
public interface IDependency
{
string GetValueOne();
string GetValueTwo();
}
I'm trying to fake the data from one of the methods (the "GetValueTwo") so its returning "expected value" instead of "get-value-two" which is what the dependency normally returns.
[Fact]
public async Task Test_SystemUnderTest()
{
using (var mock = AutoMock.GetLoose())
{
// Setup
mock.Mock<IDependency>().Setup(x => x.GetValueTwo()).Returns("expected value");
// Configure
mock.Provide<IDependency, Dependency>();
// Arrange - configure the mock
var sut = mock.Create<SystemUnderTest>();
// Act
var actual_GetValueOne = sut.GetValueOne();
var actual_GetValueTwo = sut.GetValueTwo();
// Assert - assert on the mock
Assert.Equal("get-value-one", actual_GetValueOne);
Assert.Equal("expected value", actual_GetValueTwo);
}
}
The first part in my test, the Setup piece, does not seem to have any effect, and its probably because I'm doing some basic stuff wrong.
Anyone with insights on how to save my day?
The members of Dependency implementation would need to have virtual members for them to be able to be overridden when doing a partial mocked.
public class Dependency : IDependency {
public virtual string GetValueOne() {
return "get-value-one";
}
public virtual string GetValueTwo() {
return "get-value-two";
}
}
Then similar to what was suggested in another answer you would instead mock the implementation, making sure to enable it to call base members and only setup the members you need to override.
public void Test_SystemUnderTest() {
using (var mock = AutoMock.GetLoose()) {
// Setup
var dependency = mock.Mock<Dependency>();
dependency.CallBase = true;
dependency.Setup(x => x.GetValueTwo()).Returns("expected value");
// Configure
mock.Provide<IDependency>(dependency.Object);
// Arrange - configure the mock
var sut = mock.Create<SystemUnderTest>();
// Act
var actual_GetValueOne = sut.GetValueOne();
var actual_GetValueTwo = sut.GetValueTwo();
// Assert - assert on the mock
Assert.AreEqual("get-value-one", actual_GetValueOne);
Assert.AreEqual("expected value", actual_GetValueTwo);
}
}
The above passes when exercised provided that the members of the implementation that need to be mocked can be overridden (ie virtual).
Not an expert in writing unit tests, but I'm pretty sure that by using Provide with two type arguments, you overwrite the Setup part you did previously. By my understanding, the Provide method should be used to provide your own mock implementation of target interface, so using both Provide with two type arguments and Setup for the same dependency doesn't make sense.
So you can either modify the Dependency implementation's GetValueTwo to return "expected value" and use the rest of your code unmodified, or you can supply the mocked instance to the Provide method with one type argument, with both of the methods previously setup, like this:
[Fact]
public async Task Test_SystemUnderTest()
{
using (var mock = AutoMock.GetLoose())
{
var mockedDependency = mock.Mock<IDependency>();
// Setup
mockedDependency.Setup(x => x.GetValueOne()).Returns("get-value-one");
mockedDependency.Setup(x => x.GetValueTwo()).Returns("expected value");
// The following line is not even necessary
mock.Provide<IDependency>(mockedDependency.Object);
// Arrange - configure the mock
var sut = mock.Create<SystemUnderTest>();
// Act
var actual_GetValueOne = sut.GetValueOne();
var actual_GetValueTwo = sut.GetValueTwo();
// Assert - assert on the mock
Assert.Equal("get-value-one", actual_GetValueOne);
Assert.Equal("expected value", actual_GetValueTwo);
}
}
I have a web api and I am exposing a endpoint like so:
api/Holiday?name={name}
This is the controller get method for the web api:
public IQueryable<Holiday> GetHolidayByName(string name)
{
return db.Holiday.Where(n => string.Equals(n.Name, name));
}
How can I write a unit/integration test for this that checks the names are equal? I can check the result is not null however bit confused how I can check the names are equal:
[TestMethod]
public void GetHoliday_GetHolidayByName()
{
// Arrange
HolidaysController controller = new HolidaysController();
// Act
IQueryable<Holiday> actionResult = controller.GetHolidayByName("Spain");
//Assert
Assert.IsNotNull(actionResult);
//any attempt to check names are equal results in a fail
//For instance this fails
var result = controller.GetHolidayByName("Spain") as OkNegotiatedContentResult<Holiday>;
Assert.AreEqual("Spain", result.Content.Name);
}
The test would look like this where you can use linq to verify that all the result returned satisfy your criteria.
[TestMethod]
public void GetHoliday_GetHolidayByName()
{
// Arrange
string name = "Spain";
HolidaysController controller = new HolidaysController();
// Act
IQueryable<Holiday> actionResult = controller.GetHolidayByName(name);
//Assert
Assert.IsNotNull(actionResult);
Assert.IsTrue(actionResult.All(n => string.Equals(n.Name, name));
}
The assumption here is that the db will provide you with the test data you want. Otherwise you will have to make some design changes to allow for providing mocked/fake data.
If you are connecting to an actual database then this is more an integration test rather than a unit test.
public interface IDbRepository
{
IQueryable<Holiday> GetHolidayByName(string name)
}
public class DbRepository : IDbRepository
{
public IQueryable<Holiday> GetHolidayByName(string name)
{
return db.Holiday.Where(n => string.Equals(n.Name, name));
}
}
private IDbRepository _dbRepository;//initialize, preferably through construtor
public IQueryable<Holiday> GetHolidayByName(string name)
{
return _dbRepository.GetHolidayByName(name)
}
First of all, I think that you should be testing db results but objects. Mock your method to give you "Holiday" Items, then override the "equals" method on the object, or just comparte the properties you need to check
I have following web Api controller method.
When I run this code through web, HttpContext.Current is never null and give desired value.
public override void Post([FromBody]TestDTO model)
{
var request = HttpContext.Current.Request;
var testName = request.Headers.GetValues("OS Type")[0];
// more code
}
However, when I call this method from Unit Test, HttpContext.Current is always null.
How do i fix it?
During unit tests HttpContext is always null as it is usually populate by IIS. You have a few options around this.
Sure, you could mock the HttpContext, (which you shouldn't really do - Don't mock HttpContext!!!! He doesn't like to be mocked!),. You should really try to stay away from tight coupling with HttpContext all over your code. Try constraining it to one central area (SRP);
Instead figure out what is the functionality you would like to achieve and design an abstraction around that. This will allow for your code to be more testable as it is not so tightly coupled to HttpContext.
Based on your example you are looking to access header values. This is just an example of how to change your thinking when it comes to using HttpContext.
Your original example has this
var request = HttpContext.Current.Request;
var testName = request.Headers.GetValues("OS Type")[0];
When you are looking for something like this
var testName = myService.GetOsType();
Well then create a service that provides that
public interface IHeaderService {
string GetOsType();
}
which could have a concrete implementation like
public class MyHeaderService : IHeaderService {
public string GetOsType() {
var request = HttpContext.Current.Request;
var testName = request.Headers.GetValues("OS Type")[0];
return testName;
}
}
Now in your controller you can have your abstraction instead of having tight coupling to HttpContext
public class MyApiController : ApiController {
IHeaderService myservice;
public MyApiController(IHeaderService headers) {
myservice = headers;
}
public IHttpActionResult Post([FromBody]TestDTO model) {
var testName = myService.GetOsType();
// more code
}
}
You can later inject your concrete type to get the functionality you want.
For testing you then swap dependencies to run your test.
If the method under test is your Post() method you can create a fake dependency or use a mocking framework
[TestClass]
public class MyTestClass {
public class MyFakeHeaderService : IHeaderService {
string os;
public MyFakeHeaderService(string os) {
this.os = os;
}
public string GetOsType() {
return os;
}
}
[TestMethod]
public void TestPostMethod() {
//Arrange
IHeaderService headers = new MyFakeHeaderService("FAKE OS TYPE");
var sut = new MyApiController(headers);
var model = new TestDTO();
//Act
sut.Post(model);
//Assert
//.....
}
}
This is by design and it's always null. But there is a FakeHttpContext project on Nuget that simply you can use it.
To install FakeHttpContext, run the following command in the Package Manager Console (PMC)
Install-Package FakeHttpContext
And then use it like this:
using (new FakeHttpContext())
{
HttpContext.Current.Session["mySession"] = "This is a test";
}
Visit https://www.nuget.org/packages/FakeHttpContext to install the package
See examples on Github: https://github.com/vadimzozulya/FakeHttpContext#examples
Hope this will help :)
All you need is
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
From unit-testing-controllers-in-web-api
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.
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.