I am creating Unit Tests for existing .NET Framework 4.5 API project. The existing project has parameterless constructor by design and dependency injection was implemented as per the class below using Ninject.
I would like to Mock the interface and create an instance of the class for testing as shown below but the constructor is parameterless. I can't figure out how to inject my Mock member.Object. The main goal is I don't want to change the design of existing classes unless there is no other way.
public class MemberController : ApiController
{
StandardKernel DependencyKernel;
private IMember member;
public MemberController()
{
DependencyKernel = new StandardKernel();
DependencyKernel.Load(Assembly.GetExecutingAssembly());
member = DependencyKernel.Get<IMember>();
}
[HttpPost]
public HttpResponseMessage AddMember(MemberRequest model)
{
try
{
int memberRecords;
member.SaveMember(model, out memberRecords);
if (memberRecords > 0)
return new HttpResponseMessage { StatusCode = HttpStatusCode.Conflict, Content = new StringContent("Member with same reference exists") };
else
return new HttpResponseMessage { StatusCode = HttpStatusCode.OK, Content = new StringContent("Member added successfully") };
}
catch (Exception ex)
{
return new HttpResponseMessage { StatusCode = HttpStatusCode.InternalServerError, Content = new StringContent(ex.Message) };
}
}
}
//Test Class
public class MemberControllerTests
{
StandardKernel DependencyKernel;
private MemberController memberController;
Mock<IMember> member = new Mock<IMember>();
public MemberControllerTests()
{
DependencyKernel = new StandardKernel();
DependencyKernel.Load(Assembly.GetExecutingAssembly());
}
[SetUp]
public void Setup()
{
}
[Test]
public void should_AddMember()
{
//Arrange
MemberRequest member = new MemberRequest{ };
int memberRecords;
member.Setup(x => x.SaveMember(member, out memberRecords));
memberController = new MemberController(member.Object); //This will obviously not work, the MemberController has parameterless constructor
//Act
var result = MemberController.AddMember(member);
//Assert
Assert.AreEqual(result.StatusCode, HttpStatusCode.OK);
}
}
This post has the answer to the question. If IMember member property is made public in MemberController, I can new up the MemberController class and set the value of its member property to the MOCK.
Related
I have the following classes
namespace Foo.Bar.Services
{
public abstract class Service
{
public Service(IUnitOfWork unitOfWork)
{
this.UnitOfWork = unitOfWork;
}
protected IUnitOfWork UnitOfWork { get; private set; }
}
}
using...
namespace Foo.Bar.Services
{
public class ControlService : Service
{
...
private readonly IRepository<GroupStructure> groupStructures = null;
public ControlService(IUnitOfWork uow) : base(uow)
{
...
this.agencyGroupStructures = this.UnitOfWork.GetRepository<AgencyGroupStructure>();
}
public Tuple<bool, int> HasExternalImage(int branchId)
{
var externalResultList = from a in this.Structures.Table
where a.GroupID == branch.GroupID
&& (a.AreExternalRequired == true)
&& (a.ProductTypeID == ETourType.Trailer)
&& !a.Deleted
select a;
return (some logic based on above...)
}
}
and test
namespace ControlTests
{
[TestFixture]
public class Control
{
//unable to create service due to being abstact
[Test]
public void TestMethod1()
{
******Changed here******
var Mock = new Mock<GroupStructureService> { CallBase = true };
var fakeControl = new ControlService(Mock.Object)
var sut = fakeControl.HasExternalImage(1249);
Assert.That(sut.Item1, "true");
}
}
}
Running the above with NUnit and Moq gives the following message:
Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can
not instantiate proxy of class: Foo.Bar.Services.ControlService.
Could not find a parameterless constructor.
I've tried a few things but I can't get this previously untested app to create a mock object to test
Edit, thanks. So I've changed it to use the ControlService and mock 1
dependancy. But its error is that it cant convert from
....GroupStructure to Foo.Bar.IUnitOfWork
Normally, the system under test is not mocked. Mock its dependencies and inject that into an instance of the class under test
[TestFixture]
public class Control {
[Test]
public void TestMethod1() {
//Arrange
var repository = new Mock<IRepository<GroupStructure>>();
//...Set up the repository behavior to satisfy logic
var uow = new Mock<IUnitOfWork>();
uow.Setup(_ => _.GetRepository<AgencyGroupStructure>())
.Returns(repository.Object);
var sut = new ControlService(uow.Object);
var expected = true;
//Act
var actual = sut.HasExternalImage(1249);
//Assert
Assert.AreEqual(actual.Item1, expected);
}
}
Reference Moq Quickstart to get a better understanding of how to use the mocking framework.
I have implemented generic repository in my project. Now I am writing test cases for my consumer. I am trying to mock database function through Moq but I am getting values from database rather than the one I faked through Moq. Below I am sharing my implementation. Hoping someone will help me in pointing out the mistake I made.
My interface:
public interface IEventsRepository<T> : IRepository<T> {
T GetEventsByEventId(int eventId); }
My class:
public class EventsTableRepository : EFDBRepository<EventsModel>, IEventsRepository<EventsModel> {
public EventsModel GetEventsByEventId(int eventId)
{
return _dbSet.Where(x => x.EventID == eventId).FirstOrDefault();
}
}
My Consumer:
public static Response<string> EventsAccept(EventsAlertsRequest logMsgId)
{
IEventsRepository<EventsModel> eventsRepo = (IEventsRepository<EventsModel>)RepositoryLocator.GetRepositoryObject(STMEnums.RepositoryName.EventsTableRepository.ToString());
EventsModel eventmodel = new EventsModel();
eventmodel = eventsRepo.GetEventsByEventId(eachlogMsgId);
return EventStatusChangeResponse;
}
Test Method:
public void EventsAcceptSuccessTest()
{
EventsModel eventmodel = new EventsModel();
eventmodel.Message = "TEST";
Mock<IEventsRepository<EventsModel>> obj = new Mock<IEventsRepository<EventsModel>>();
obj.Setup(m => m.GetEventsByEventId(Moq.It.IsAny<int>())).Returns(eventmodel);
EventStatusChangeResponse = Diagnostics_.EventsAccept(logMsgId);
Assert.AreEqual(eventmodel.Status, EventStatus.ACCEPTED);
}
No where in the provided example is the mock being injected into the subject under test. Also it looks like the subject method under test is using static Service Locator anti-pattern to get the desired model. Making an assumption here as the rest of the class is not shown in relation to that variable.
The locator would need to have been an injected abstraction to allow an opportunity to mock its expected behavior
public class Consumer {
private IRepositoryLocator RepositoryLocator;
public Consumer(IRepositoryLocator RepositoryLocator) {
this.RepositoryLocator = RepositoryLocator;
}
public Response<string> EventsAccept(EventsAlertsRequest logMsgId) {
IEventsRepository<EventsModel> eventsRepo = (IEventsRepository<EventsModel>)RepositoryLocator.GetRepositoryObject(STMEnums.RepositoryName.EventsTableRepository.ToString());
EventsModel eventmodel = new EventsModel();
eventmodel = eventsRepo.GetEventsByEventId(eachlogMsgId);
return EventStatusChangeResponse;
}
}
This would then mean that the locator would also have to be mocked properly for the test to be exercised to completion.
public void EventsAcceptSuccessTest() {
//Arrange
var eventmodel = new EventsModel() {
Message = "TEST"
};
var repositoryMock = new Mock<IEventsRepository<EventsModel>>();
repositoryMock
.Setup(_ => _.GetEventsByEventId(It.IsAny<int>()))
.Callback((int id) => {
eventmodel.EventID = id;
eventmodel.Status = EventStatus.ACCEPTED;
})
.Returns(eventmodel);
var locatorMock = new Mock<IRepositoryLocator>();
locatorMock.Setup(_ => _.GetRepositoryObject(It.IsAny<string>())).Returns(repositoryMock.Object);
var subject = new Consumer(locatorMock.Object);
//Act
var response = subject.EventsAccept(logMsgId);
//Assert
Assert.AreEqual(eventmodel.Status, EventStatus.ACCEPTED);
}
I have class to setup Autofac in my WebApi project, it's look like:
public static class Bootstraper
{
private static IContainer _container { get; set; }
public static void Init()
{
var configuration = GlobalConfiguration.Configuration;
var builder = new ContainerBuilder();
// register WebAPI
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(configuration);
builder.RegisterHttpRequestMessage(configuration);
// register MVC
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterModule(new AutofacWebTypesModule());
// register model class
builder.RegisterType<Foo>().AsSelf().InstancePerRequest();
builder.RegisterType<FooMessage>().AsSelf().InstancePerRequest();
var container = builder.Build();
// setup WebApi Autofac resolver
var resolverAPI = new AutofacWebApiDependencyResolver(container);
configuration.DependencyResolver = resolverAPI;
// setup MVC Autofac resolver
var resolverMVC = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(resolverMVC);
_container = container;
}
public static T Resolve<T>()
{
return _container.Resolve<T>();
}
public static T ResolveInScope<T>()
{
// where scope shoud by disposed?
var scope = _container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
return scope.Resolve<T>();
}
}
Foo and FooMessage class:
public class FooMessage
{
public HttpRequestMessage Request {get; private set; }
public Foo Foo { get; private set; }
public FooMessage(HttpRequestMessage requestMessage, Foo fooo)
{
Request = requestMessage;
Foo = fooo;
}
}
public class Foo
{
public static int counter = 0;
public int Index { get; private set; }
public Foo()
{
Index = counter++;
}
}
To show my problem, I prepared example controller
public class ValuesController : ApiController
{
private FooMessage fooMessage;
private Foo foo;
public ValuesController(FooMessage fm, Foo fooo)
{
fooMessage = fm;
foo = fooo;
}
// GET api/values
public bool Get()
{
// it works but create new Foo object (resolvedFoo.Index > foo.Index)
var resolvedFoo = DependencyResolver.Current.GetService<Foo>();
// throw the exception
var resolvedFoo2 = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(Foo)) as Foo;
// throw the Exception
var resolvedFoo3 = Bootstraper.Resolve<Foo>();
// it works but create new Foo object (resolvedFoo.Index > foo.Index)
// and I don't now when dispose created scope
var resolvedFoo4 = Bootstraper.ResolveInScope<Foo>();
if (resolvedFoo.Index != foo.Index || resolvedFoo.Index != fooMessage.Foo.Index)
return false;
return true;
}
}
When the ValuesController is created the Index properties in foo and fooMessage.Foo has the same value, it works greate. I need resolve Foo, FooMessage and especially HttpRequestMessage in my bussines logic (InstancePerRequest) but I can't use bussines constructor to do this. For my purpose best solution would by use Bootstraper.Resolve() but it throw the exception:
An exception of type 'Autofac.Core.DependencyResolutionException'
occurred in Autofac.dll but was not handled in user code
Additional information: No scope with a Tag matching
'AutofacWebRequest' is visible from the scope in which the instance
was requested. This generally indicates that a component registered as
per-HTTP request is being requested by a SingleInstance() component
(or a similar scenario.) Under the web integration always request
dependencies from the DependencyResolver.Current or
ILifetimeScopeProvider.RequestLifetime, never from the container
itself.
Please, help me to understand how it shoud work.
I'm trying to Setup a Mock call to a the IModelFactory interface that I have.
here is the IModelFactory interface
public interface IModelFactory
{
MaterialAcceptedModel Create(MaterialAccepted model);
MaterialAccepted Parse(MaterialAcceptedModel model);
}
This is the ModelFactory class which implements the IModelFactor interface (I've only add here the method I'm trying to test, no need to add the implementation of the Create Method)
public class ModelFactory : IModelFactory
{
private UrlHelper _urlHelper;
private IRTWRepository _repo;
//private IKeysGeneratorService _keysGen;
private IGeocodeService _geocoder;
public ModelFactory(HttpRequestMessage request, IRTWRepository repo,IGeocodeService geocoder)
{
_urlHelper = new UrlHelper(request);
_repo = repo;
_geocoder = geocoder;
}
#region Parses
public MaterialAccepted Parse(MaterialAcceptedModel model)
{
try
{
if (!string.IsNullOrWhiteSpace(model.category))
{
var category = _repo.CategoryRepository.Get(model.category);
if (category == null) return null;
var entry = new MaterialAccepted()
{
business = model.business,
businessService = model.businessService,
residential = model.residential,
residentialService = model.residentialService,
note = model.note,
Category = category
};
return entry;
}
return null;
}
catch
{
return null;
}
}
#endregion
}
I'm using a BaseAPiController that contains the repo and configuration Interfaces
public class BaseApiController : ApiController
{
IRTWRepository _repository;
IModelFactory _modelFactory;
IConfiguration _configuration;
IGeocodeService _geocoder;
public BaseApiController(IRTWRepository repository,IConfiguration configuration)
{
_repository = repository;
_configuration = configuration;
}
protected IRTWRepository TheRepository
{
get
{
return _repository;
}
}
protected IConfiguration TheConfiguration
{
get
{
return _configuration;
}
}
protected IModelFactory TheModelFactory
{
get
{
_geocoder = new GeocodeService(_configuration.GetValue("geocodeGoogleApiKey"));
if (_modelFactory == null)
{
_modelFactory = new ModelFactory(this.Request, _repository,_geocoder);
}
return _modelFactory;
}
}
Here is the action method in the controller I'm trying to test
[HttpPost]
[Route("api/recyclecenters/{rcid}/materials/")]
public IHttpActionResult Post(int rcid, [FromBody]MaterialAcceptedModel model)
{
try
{
if (model != null)
{
var recycleCenter = TheRepository.RecycleCenterRepository.Get(rcid);
if (recycleCenter == null)
return NotFound();
if (!ModelState.IsValid)
return BadRequest(ModelState);
var entity = TheModelFactory.Parse(model);
if (entity == null) return BadRequest("Could not read material accepted in body");
if (TheRepository.MaterialAcceptedRepository.Get(recycleCenter.RecycleCenterId, entity.Category.name) != null)
return Conflict();
recycleCenter.Materials.Add(entity);
if (TheRepository.SaveAll())
{
string locationHeader = Url.Link("Materials", new { rcid = rcid, name = model.category.ToLower() });
return Created<MaterialAcceptedModel>(locationHeader, TheModelFactory.Create(entity));
}
return BadRequest("Could not save to the database");
}
return BadRequest();
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
This is the line that returns null even though I mocked it up on my test method
var entity = TheModelFactory.Parse(model);
and this one is my TestClass
namespace API.Tests.Web
{
[TestClass]
public class MaterialsControllerTest
{
private Mock<IRTWRepository> repository;
private Mock<IModelFactory> factory;
private Mock<IConfiguration> configuration;
private Mock<IRTWAPIIdentityService> identityService;
private MaterialsController controller;
RecycleCenter recycleCenter;
private MaterialAccepted CreateMaterial()
{
return new MaterialAccepted()
{
business = true,
businessService = EnumRecycleCenterService.Dropoff,
residential = false,
residentialService = EnumRecycleCenterService.Pickup,
note = "this a note",
Category = new Category()
{
name = "Books"
}
};
}
[TestInitialize]
public void Initialize()
{
repository = new Mock<IRTWRepository>();
factory = new Mock<IModelFactory>();
configuration = new Mock<IConfiguration>();
identityService = new Mock<IRTWAPIIdentityService>();
controller = new MaterialsController(repository.Object,configuration.Object);
controller.Request = new HttpRequestMessage();
recycleCenter = new RecycleCenter(){RecycleCenterId = 1};
}
[TestMethod]
public void Post_ShouldReturnConflictIfTheRecycleCenterAlreadyTakesMaterial()
{
//arrange
repository.Setup(r => r.RecycleCenterRepository.Get(It.IsAny<int>())).Returns(() => recycleCenter);
factory.Setup(f => f.Parse(new MaterialAcceptedModel())).Returns(() => new MaterialAccepted());
configuration.Setup(c => c.GetValue(It.IsAny<string>())).Returns(() => "APIKEY");
repository.Setup(r => r.MaterialAcceptedRepository.Get(It.IsAny<int>(), It.IsAny<string>())).Returns(() => null);
//act
var actionResult = controller.Post(It.IsAny<int>(),new MaterialAcceptedModel());
//assert
Assert.IsInstanceOfType(actionResult, typeof(ConflictResult));
}
}
}
This is the line that's not working because it always return null instead of a new instance of MaterialAccepted
factory.Setup(f => f.Parse(new MaterialAcceptedModel())).Returns(() => new MaterialAccepted());
I tried f.Parse(It.IsAny()) but still doesn't work.
To clarify
the above line of code is returning null because is not mocking the f.Parse() call, instead is executing it and returning null because the if condition I have on that method
Anyone could explain why the Setup is not working?
Setting up your Mock using It.IsAny will work:
factory.Setup(f => f.Parse(It.IsAny<MaterialAcceptedModel>()))
.Returns(() => new MaterialAccepted());
However, as has been said by #Macilquham, I can't see where your are passing the Mock to your controller in the supplied code so that it is used by the production code.
If you don't call the method on your Mock object, which you don't, you're currently calling the method on the instance of the real object created by your base class, then it doesn't matter how you set up your mock it's not going to work. If you are able to change your base class, then doing something like this would allow you to work around your problem:
// Add defaulted parameter to base class to allow modelFactory creation
// to be overridden/injected (this will prevent the current default behaviour
// when fetching the factory, if a non-null is passed in)
public BaseApiController(IRTWRepository repository,IConfiguration configuration,
IModelFactory modelFactory = null)
{
_modelFactory = modelFactory;
}
Modify your sut constructor to allow you to supply a modelFactory (again, default it to null), then amend your test as appropriate:
controller = new MaterialsController(repository.Object,configuration.Object,
factory.Object);
You don't seem to be injecting in the IModelFactory into the controller. You need to make sure that your production code is using the Mock you are setting up in the test.
Mock cannot return null directly.
The trick is just to create a null object.
Assuming the object returned is of type class Material:
Material nullMaterial = null;
...
repository.Setup(r => r.MaterialAcceptedRepository
.Get(It.IsAny<int>(), It.IsAny<string>()))
.Returns(nullMaterial);
This should solve your problem
Not sure how I can fix this, trying to do a unit test on the method "GetByTitle"
Here are my definitions:
public class ArticleDAO : GenericNHibernateDAO(IArticle, int>, IArticleDAO
{
public IArticle GetByTitle(string title)
{
IQuery query = Session.CreateQuery("...")
return query.UniqueResult<IArticle>();
}
}
public interface IArticleDAO
{
IArticle GetByTitle(string title);
}
unit test:
[Test]
public void can_load_by_title()
{
_mockDaoFactory.Setup(x => x.GetArticleDao())
.Returns(_mockArticleDao.Object);
_mockArticleDao.Setup(x => x.GetByTitle("some title"))
.Returns(article1.Object);
_articleManager.LoadArticle("some title");
Assert.IsNotNull(_articleManager.Article);
}
Running the test gives me the error:
System.ArgumentException: Invalid setup on a non-overridable member:
x => x.GetByTitle("some title")
Update
My [Setup] looks like:
[Setup]
public void SetUp()
{
_mockDaoFactory = new Mock<IDaoFactory>();
_mockArticleDao = new Mock<ArticleDao>();
_articleManager = new ArticleManager(_mockDaoFactory.Object);
}
In order to control the behavior of a mock object (in Moq, at least), you either need to mock an interface, or make sure that the behavior you're trying to control is marked virtual. In your comment, I understand it so that the instantiating of _mockArticleDao is done something like this:
_mockArticleDao = new Mock<ArticleDAO>();
If you want to keep it as so, you need to mark the GetArticle method virtual:
public class ArticleDAO : GenericNHibernateDAO(IArticle, int>, IArticleDAO
{
public virtual IArticle GetByTitle(string title)
{
// ...
}
}
Otherwise (and this is what I recommend), mock the interface instead.
_mockArticleDao = new Mock<IArticleDAO>();
Create an inherited mockable class
I had the same issue trying to mock a class I have no control over, from a framework. In my specific case I had to mock an HttpResponseMessage setting up the status code to return Ok, but how to do it if that property is not virtual?
This code does not work because StatusCode is not virtual:
var httpResponseMessage = new Mock<HttpResponseMessage>();
httpResponseMessage.SetupGet(x => x.StatusCode).Returns(HttpStatusCode.OK);
Answer:
Create a new class in your test project, inheriting from the class you want to mock
Redefine the same set of constructors calling the base constructors
Redefine the non virtual properties or methods you want to setup as virtual (use the new keyword to explicitly hide the original members)
From the redefined virtual properties or methods, call the non virtual base property or method.
Done. Now you can mock a derived object that can be used anywhere the original one is used, because it inherits from it. Here is the code for my MockableHttpResponseMessage class:
public class MockableHttpResponseMessage: HttpResponseMessage
{
public MockableHttpResponseMessage() : base() {}
public MockableHttpResponseMessage(HttpStatusCode code) : base (code) { }
public new virtual HttpStatusCode StatusCode {
get { return base.StatusCode; }
set { base.StatusCode = value; }
}
}
Now, this code works:
var httpResponseMessage = new Mock<MockableHttpResponseMessage>();
httpResponseMessage.SetupGet(x => x.StatusCode).Returns(HttpStatusCode.OK);
Here's how I Mock HttpMessageHandler:
private HttpRequestMessage requestMessage = new HttpRequestMessage();
Mock<HttpMessageHandler> handlerMock =
GetHttpMessageHandlerMock(HttpStatusCode.OK);
MyRestService myRestService = new MyRestService();
myRestService.client = new HttpClient(handlerMock.Object);
var response = myRestService.Get("");
//At this point, the Mock of HttpRequestMessage is called and the Callback fills my class variable requestMessage. I can now look inside the requestMessage.
var headers = requestMessage?.Headers.ToString();
var queryBegin = requestMessage.RequestUri.OriginalString.IndexOf('?');
var queryString = requestMessage.RequestUri.OriginalString.Substring(queryBegin + 1);
Assert.That(headers.Contains("x-api-key: fakeApiKey"));
//Helper methods below
private Mock<HttpMessageHandler> GetHttpMessageHandlerMock(HttpStatusCode statusCode)
{
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
handlerMock
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>()
, ItExpr.IsAny<CancellationToken>()
)
.Returns(Task.FromResult(GetFakeResponse(statusCode)))
.Callback<HttpRequestMessage, CancellationToken>((p, q) => requestMessage = p)
.Verifiable();
return handlerMock;
}
private HttpResponseMessage GetFakeResponse(HttpStatusCode statusCode)
{
var s = "{\"data\":{\"status\":\"SUCCESS\",\"errorCode\":\"\",\"errorMessage\":\"9\"}}";
HttpResponseMessage response = new HttpResponseMessage()
{
StatusCode = statusCode,
Content = new StringContent(s),
ReasonPhrase = "OK",
RequestMessage = new HttpRequestMessage()
};
return response;
}
I use this for almost all my REST tests, because I can pass in status, content, etc. So, I can test different return values.