AutoFixture AutoMoq problem getting CallBase to work with injected Mock dependencies - c#

I'm using AutoFixture to create a service which has a repository dependency injected through the constructor. When using fixture.Create<>, a mock repository is automatically provided for the dependency. I'd like to use CallBase on the mock repository so that it calls the method on the actual underlying class. Is this possible? The methods are defined as virtual so that Moq can override them. Below is a basic example and a test with AutoFixture which fails. Then the same test is shown using Moq directly which succeeds. The testing library being used is xUnit. Assume the interfaces have the shown methods defined.
Service:
public class PersonService : IPersonService {
private readonly IPersonRepository _personRepository;
public PersonService(IPersonRepository personRepository) {
_personRepository = personRepository;
}
public virtual string GetPersonName(int id) => _personRepository.GetPersonName(id);
}
Repository:
public class PersonRepository : IPersonRepository {
public virtual string GetPersonName(int id) => Data.People[id].FirstName!;
}
Data:
public static class Data {
public static List<Person> People { get; } = new() {
new Person { FirstName = "Jack" },
new Person { FirstName = "Jill" }
};
}
Person:
public class Person {
public string? FirstName { get; set; }
}
Failing Test with AutoFixture: result is null, the GetPersonName method on the repo is never called via CallBase
[Fact]
public void AutoFixture_Test_CallBase() {
var fixture = new Fixture();
fixture.Customize(new AutoMoqCustomization());
var mockPersonRepository = fixture.Freeze<Mock<PersonRepository>>();
mockPersonRepository.Setup(r => r.GetPersonName(It.IsAny<int>())).CallBase();
var sut = fixture.Create<PersonService>();
var result = sut.GetPersonName(1);
Assert.Equal(Data.People[1].FirstName, result);
}
The same test works fine using Moq without AutoFixture:
[Fact]
public void Moq_Test_CallBase() {
var mockPersonRepository = new Mock<PersonRepository>();
mockPersonRepository.Setup(r => r.GetPersonName(It.IsAny<int>())).CallBase();
var sut = new PersonService(mockPersonRepository.Object);
var result = sut.GetPersonName(1);
Assert.Equal(Data.People[1].FirstName, result);
}

The problem is that when PersonService is created by AutoFixture, it uses the Mock<IPersonRepository> to build up an IPersonRepository but in your code it is not defined so it uses the default.
Since you want to setup the Mock<IPersonRepository> with CallBase, one approach would be to freeze a Mock<PersonRepository> and then, whenever an IPersonRepository is required by AutoFixture to build up any other object that depends on it (like the PersonService) you call fixture.Create<PersonRepository>()
So it'd be like this:
[Fact]
public void AutoFixture_Test_CallBase()
{
var fixture = new Fixture();
fixture.Customize(new AutoMoqCustomization());
var mockPersonRepository = fixture.Freeze<Mock<PersonRepository>>();
mockPersonRepository
.Setup(r => r.GetPersonName(It.IsAny<int>()))
.CallBase();
fixture.Register<IPersonRepository>(() => fixture.Create<PersonRepository>());
var sut = fixture.Create<PersonService>();
var result = sut.GetPersonName(1);
Assert.Equal(Data.People[1].FirstName, result);
}

Related

AutoFixture multiple customization wont work

AutoFixture will not work with register and additional customize call. If I do only one of the two, it works. The whole behavior of customize feature is hard to understand for me. Is this works as designed?
Goal: Use the greediest constructor AND OmitAutoProperties for special class.
public interface IDataProvider { }
public class FileDataProvider : IDataProvider {}
public class TestClass
{
public TestClass() : this (new FileDataProvider()) { }
public TestClass(IDataProvider dataProvider) { } // should be used from AutoFixture
}
[Fact]
public void Method_State_Result()
{
var fixture = new Fixture();
fixture.Register(() => fixture.Build<TestClass>().OmitAutoProperties().Create());
var dc1 = fixture.Create<TestClass>(); // working
fixture.Customize(new AutoNSubstituteCustomization());
fixture.Customizations.Add(new MethodInvoker(new GreedyConstructorQuery()));
var dc2 = fixture.Create<TestClass>(); // crash with "AutoFixture was unable to create an instance from System.SByte*, most likely because it has no public constructor, is an abstract or non-public type"
var dc3 = fixture.Create<TestClass>();
}
A workaround would be to do the registration like this. But feels not like the right solution...
fixture.Register(() => new Fixture().Build<TestClass>().OmitAutoProperties().Create());
If I understood the question correctly, then the easiest option is to provide a custom factory that uses a specimen builder.
fixture.Customize<TestClass>(c => c
.FromFactory(new MethodInvoker(new GreedyConstructorQuery()))
.OmitAutoProperties());
Here is a sample test.
public class TestClass
{
public TestClass() : this(new FileDataProvider())
{
}
public TestClass(IDataProvider dataProvider)
{
DataProvider = dataProvider;
}
public string SomeString { get; set; }
public IDataProvider DataProvider { get; }
}
[Fact]
public void FooTest()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
fixture.Customize<TestClass>(c => c
.FromFactory(new MethodInvoker(new GreedyConstructorQuery()))
.OmitAutoProperties());
var mockProvider = fixture.Freeze<IDataProvider>();
var testObject = fixture.Create<TestClass>();
Assert.Null(testObject.SomeString);
Assert.Same(mockProvider, testObject.DataProvider);
}

How to test method in unit testing

I have such service as below. Let's say i want to test Create() method. I read that in unit testing i should test by comparing, counting and so on. How could i then test my Create() method. Is it ugly to change return type from void Create to bool Create just to be able to check method output for testing purpose or that's not ideal idea? Can you propose something?
public class CreateCarService : ICreateCarService
{
private readonly ICarQuery _carQuery;
private readonly ICarRepository _carRepository;
public CreateCarService(ICarQuery carQuery, ICarRepository carRepository)
{
_carQuery = carQuery;
_carRepository = carRepository;
}
public void Create(Car car)
{
if (car == null) throw new CusException(Error, "Car object cannot be null");
if (_carQuery.IsLoginExist(car.Login))
throw new CusException(Error, "Message1");
if (_carQuery.IsEmailExist(car.Email))
throw new CusException(Error, "Message1");
_carRepository.Add(car);
}
}
You might verify that for any valid Car instance Add method was called only once, by setting up the Moq behavior of IsLoginExist and IsEmailExist method an using a Verify method
[TestFixture]
public class Test
{
[Test]
public void CreateCarServiceTest()
{
var carQueryMock = new Mock<ICarQuery>();
var carRepositoryMock = new Mock<ICarRepository>();
var createCarService = new CreateCarService(carQueryMock.Object, carRepositoryMock.Object);
carQueryMock.Setup(c => c.IsLoginExist(It.IsAny<string>())).Returns(false);
carQueryMock.Setup(c => c.IsEmailExist(It.IsAny<string>())).Returns(false);
createCarService.Create(new Car());
carRepositoryMock.Verify(c => c.Add(It.IsAny<Car>()), Times.Once);
}
}
It also makes sense to check a negative cases, when Create method throws an exception
[Test]
public void CreateCarNegativeTest()
{
var carQueryMock = new Mock<ICarQuery>();
var carRepositoryMock = new Mock<ICarRepository>();
var createCarService = new CreateCarService(carQueryMock.Object, carRepositoryMock.Object);
Assert.Throws<CusException>(() => createCarService.Create(null));
carQueryMock.Setup(c => c.IsLoginExist(It.IsAny<string>())).Returns(true);
Assert.Throws<CusException>(() => createCarService.Create(new Car()));
carQueryMock.Setup(c => c.IsLoginExist(It.IsAny<string>())).Returns(false);
carQueryMock.Setup(c => c.IsEmailExist(It.IsAny<string>())).Returns(true);
Assert.Throws<CusException>(() => createCarService.Create(new Car()));
}
You can split this method into different tests to have one Assert per test, or pass the parameters to it.
You want to test the "expected behavior" of the member under test. Since the member under test does not return any verifiable output and has a dependency on external abstractions, you should be able to monitor the interaction of the member under test with that external abstractions and verify the expected behavior
One such example
public void CreateCarService_Create_Should_Add_Car() {
//Arrange
Car car = new Car {
Login = "Login",
Email = "Email"
};
ICarQuery carQuery = Mock.Of<ICarQuery>();
ICarRepository carRepository = Mock.Of<ICarRepository>();
ICreateCarService subject = new CreateCarService(carQuery, carRepository);
//Act
subject.Create(car);
//Assert
Mock.Get(carRepository).Verify(_ => _.Add(car), Times.Once);
}
The example above safely navigates through to the end of the member under test but lets say you wanted to test the exception is thrown for the null parameter case.
public void CreateCarService_Create_Should_Throw_CusException_For_Null_Car() {
//Arrange
ICreateCarService subject = new CreateCarService(null, null);
//Act
Action act = ()=> subject.Create(null);
//Assert
var ex = Assert.Throws<CusException>(act);
}
You want to create tests for all the possible paths through the member under test. So take some time and review the subject under test and work out the possible test cases. Arrange the subject to satisfy those cases and exercise those cases to verify the expected behavior.
Reference Moq Quickstart to get a better understanding of how to use the Moq mocking framework.
You don't need to change it to bool, just to test. A simple way you can do this is:
[TestFixture]
public class Test
{
CreateCarService createCarService;
ICarRepository carRepositoryMock;
[Setup]
public void InitializeTest()
{
var carQueryMock = new Mock<ICarQuery>();
carRepositoryMock = new Mock<ICarRepository>();
createCarService = new CreateCarService(carQueryMock.Object, carRepositoryMock.Object);
}
[Test]
public void CreateCarShouldThrowIfNull()
{
//arrange
Car car =null;
//act and assert
Assert.Throw<CustomException>(()=>
{
createCarService.CreateCar(car);
});
}
[Test]
public void CreateCarShouldThrowForInvalidLogin()
{
//arrange
var car = new Car()
{
Login=null,
Email="Email"
};
//act and assert
Assert.Throw<CustomException>(()=>
{
createCarService.CreateCar(car);
});
}
And So on.
You can use Assert.Throw for invalid car objects or Assert.DoesNotThrow for valid car objects. Finally, you can test if the car was added to the repository by:
[Test]
public void CreateCarShouldAddCarToRepo()
{
//arrange
var car = new Car()
{
Login="Login",
Email="Email"
};
//act
createCarService.CreateCar(car);
var carRetrieved =carRepositoryMock.GetCar(car.id);//depending on your implementation
//assert
Assert.AreSame(car,carRetrieved);
}

Issue in unit testing and using Moq .Returns

I am new to write Unit Tests. Therefore, I have been struggling with.
I need to insert product via an external WebService. Then the WebService will return a string that is necessary to update the product afterwards.
This is my ApiController:
public class ProductController : ApiController
{
private IProductRepository _ProductRepository;
private IWebService _WebService;
public ProductController(IProductRepository productRepository, IWebService webService)
{
_ProductRepository = productRepository;
_WebService = webService;
}
public HttpResponseMessage Add(string title)
{
using (TransactionScope scope = new TransactionScope())
{
Product product = new Product
{
Title = title
};
this._ProductRepository.Add(product);
// WebService will return a string
string result = this._WebService.Add(product.ID, DateTime.Now);
product.ServiceResult = result;
this._ProductRepository.Update(product);
scope.Complete();
}
return Request.CreateResponse(HttpStatusCode.Created);
}
}
I was wondering how should I write a unit test for this code?
I've tried to write it as follows: (with NUnit, Moq)
[TestFixture]
public class ProductControllerShould : AssertionHelper
{
private Mock<IWebService> _WebService;
private Mock<IProductRepository> _ProductRepository;
[SetUp]
public void Setup()
{
_WebService = new Mock<IWebService>();
_ProductRepository = new Mock<IProductRepository>();
}
[Test]
public void ReturnCreatedOnAdd()
{
_WebService.Setup(b => b.Add(1, DateTime.Now))
.Returns("0");
var controller = new ProductController(_ProductRepository.Object,
_WebService.Object);
var result = controller.Add("Lumia");
Expect(result, Is.EqualTo(HttpStatusCode.Created));
}
}
but when I debug the test, result in this line is null that is not correct.
string result = this._WebService.Add(product.ID, DateTime.Now);
Shouldn't this line handle the behaviour of _WebService.Add() and return "0"?
_WebService.Setup(b => b.Add(1, DateTime.Now))
.Returns("0");
I know I write the test incorrectly but I don't know what should I do.
Thanks.
The problem here, is that you are mocking call of static method `DateTime.Now' . But "Now" in the time point of mocking and as it is called are different. Therefore your call doesn't return anything.
I could suggest 3 following ways:
1) It doesn't really matter for you, if the call was with DateTime.Now or not, in that case you could ignore the second argument:
_WebService.Setup(b => b.Add(1, It.IsAny<DateTime>())).Returns("0");
2) You want to test, that the call was with DateTime.Now. In that case i create an interface for getting DateTime.Now:
public interface IDateTimeNowProvider
{
DateTime Now { get; }
}
public ProductController(IProductRepository productRepository,
IWebService webService,
IDateTimeNowProvider dateTimeNowProvider)
{
_ProductRepository = productRepository;
_WebService = webService;
_dateTimeNowProvider = dateTimeNowProvider;
}
In production code you use default implementation of it, that just returns DateTime.Now. But in your test class you do mock this interface with some predefined values and you test for using this value.
var now = DateTime.Parse("2017-01-22");
var _dateTimeNowProvider = new Mock<IDateTimeNowProvider>();
var controller = new ProductController(_ProductRepository.Object,
_WebService.Object, _dateTimeNowProvider.Object );
_dateTimeNowProvider.Setup(x => x.Now).Returns(now);
_WebService.Setup(b => b.Add(1,now)).Returns("0");
3) You could use special mocking framework that allows to mock static methods, as for example typemock isolator

Creating a hybrid of a mock and an anonymous object using e.g. Moq and AutoFixture?

I encountered a class during my work that looks like this:
public class MyObject
{
public int? A {get; set;}
public int? B {get; set;}
public int? C {get; set;}
public virtual int? GetSomeValue()
{
//simplified behavior:
return A ?? B ?? C;
}
}
The issue is that I have some code that accesses A, B and C and calls the GetSomeValue() method (now, I'd say this is not a good design, but sometimes my hands are tied ;-)). I want to create a mock of this object, which, at the same time, has A, B and C set to some values. So, when I use moq as such:
var m = new Mock<MyObject>() { DefaultValue = DefaultValue.Mock };
lets me setup a result on GetSomeValue() method, but all the properties are set to null (and setting up all of them using Setup() is quite cumbersome, since the real object is a nasty data object and has more properties than in above simplified example).
So on the other hand, using AutoFixture like this:
var fixture = new Fixture();
var anyMyObject = fixture.CreateAnonymous<MyObject>();
Leaves me without the ability to stup a call to GetSomeValue() method.
Is there any way to combine the two, to have anonymous values and the ability to setup call results?
Edit
Based on nemesv's answer, I derived the following utility method (hope I got it right):
public static Mock<T> AnonymousMock<T>() where T : class
{
var mock = new Mock<T>();
fixture.Customize<T>(c => c.FromFactory(() => mock.Object));
fixture.CreateAnonymous<T>();
fixture.Customizations.RemoveAt(0);
return mock;
}
This is actually possible to do with AutoFixture, but it does require a bit of tweaking. The extensibility points are all there, but I admit that in this case, the solution isn't particularly discoverable.
It becomes even harder if you want it to work with nested/complex types.
Given the MyObject class above, as well as this MyParent class:
public class MyParent
{
public MyObject Object { get; set; }
public string Text { get; set; }
}
these unit tests all pass:
public class Scenario
{
[Fact]
public void CreateMyObject()
{
var fixture = new Fixture().Customize(new MockHybridCustomization());
var actual = fixture.CreateAnonymous<MyObject>();
Assert.NotNull(actual.A);
Assert.NotNull(actual.B);
Assert.NotNull(actual.C);
}
[Fact]
public void MyObjectIsMock()
{
var fixture = new Fixture().Customize(new MockHybridCustomization());
var actual = fixture.CreateAnonymous<MyObject>();
Assert.NotNull(Mock.Get(actual));
}
[Fact]
public void CreateMyParent()
{
var fixture = new Fixture().Customize(new MockHybridCustomization());
var actual = fixture.CreateAnonymous<MyParent>();
Assert.NotNull(actual.Object);
Assert.NotNull(actual.Text);
Assert.NotNull(Mock.Get(actual.Object));
}
[Fact]
public void MyParentIsMock()
{
var fixture = new Fixture().Customize(new MockHybridCustomization());
var actual = fixture.CreateAnonymous<MyParent>();
Assert.NotNull(Mock.Get(actual));
}
}
What's in MockHybridCustomization? This:
public class MockHybridCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(
new MockPostprocessor(
new MethodInvoker(
new MockConstructorQuery())));
fixture.Customizations.Add(
new Postprocessor(
new MockRelay(t =>
t == typeof(MyObject) || t == typeof(MyParent)),
new AutoExceptMoqPropertiesCommand().Execute,
new AnyTypeSpecification()));
}
}
The MockPostprocessor, MockConstructorQuery and MockRelay classes are defined in the AutoMoq extension to AutoFixture, so you'll need to add a reference to this library. However, note that it's not required to add the AutoMoqCustomization.
The AutoExceptMoqPropertiesCommand class is also custom-built for the occasion:
public class AutoExceptMoqPropertiesCommand : AutoPropertiesCommand<object>
{
public AutoExceptMoqPropertiesCommand()
: base(new NoInterceptorsSpecification())
{
}
protected override Type GetSpecimenType(object specimen)
{
return specimen.GetType();
}
private class NoInterceptorsSpecification : IRequestSpecification
{
public bool IsSatisfiedBy(object request)
{
var fi = request as FieldInfo;
if (fi != null)
{
if (fi.Name == "__interceptors")
return false;
}
return true;
}
}
}
This solution provides a general solution to the question. However, it hasn't been extensively tested, so I'd love to get feedback on it.
Probably there is a better why, but this works:
var fixture = new Fixture();
var moq = new Mock<MyObject>() { DefaultValue = DefaultValue.Mock };
moq.Setup(m => m.GetSomeValue()).Returns(3);
fixture.Customize<MyObject>(c => c.FromFactory(() => moq.Object));
var anyMyObject = fixture.CreateAnonymous<MyObject>();
Assert.AreEqual(3, anyMyObject.GetSomeValue());
Assert.IsNotNull(anyMyObject.A);
//...
Initially I tried to use fixture.Register(() => moq.Object); instead of fixture.Customize but it registers the creator function with OmitAutoProperties() so it wouldn't work for you case.
As of 3.20.0, you can use AutoConfiguredMoqCustomization. This will automatically configure all mocks so that their members' return values are generated by AutoFixture.
var fixture = new Fixture().Customize(new AutoConfiguredMoqCustomization());
var mock = fixture.Create<Mock<MyObject>>();
Assert.NotNull(mock.Object.A);
Assert.NotNull(mock.Object.B);
Assert.NotNull(mock.Object.C);

Moq.Mock<T> setting up expressions into a Mock using MOQ results in mock setups not being matched

I am trying to mock out a data service context, as part of this I have a method which takes in
an expression (predicate),
an optional string parameter
a params with an array of predicates.
when I try to mock this method out, MOQ always returns a
All invocations on the mock must have a corresponding setup.
TearDown : Moq.MockException : The following setups were not matched:
IContext m => m.Retrieve(It.IsAny() })
code below of the interface/implementation
public interface IContext
{
IQueryable<T> Retrieve<T>(Expression<Func<T, bool>> predicate,
string entitySetName = null,
params Expression<Func<T, object>>[] eagerProperties);
}
public class Context : IContext
{
private readonly DataServiceContext _context;
public Context(DataServiceContext context)
{
this._context = context;
}
public IQueryable<T> Retrieve<T>(Expression<Func<T, bool>> predicate,
string entitySetName = null,
params Expression<Func<T, object>>[] eagerProperties)
{
DataServiceQuery<T> query = _context.CreateQuery<T>(entitySetName ?? "Default");
return eagerProperties.Aggregate(query, (current, e) => current.Expand(e.ToString())).Where(predicate);
}
}
The below is a test class that calls the above context method
public class Test
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
}
public class SomeController
{
private IContext _context = new Context(
new DataServiceContext(new Uri("http://whatever/someservice.svc/")));
public IContext ServiceContext
{
get
{
return _context ??
(_context = new Context(new DataServiceContext(new Uri("http://whatever/someservice.svc/"))));
}
set
{
_context = value;
}
}
public Test RetrieveSomeInformation()
{
IQueryable<Test> tests = _context.Retrieve<Test>
(
//Param 1
t => t.Prop1 == "test" && 1 == 1,
//Param 2
"Test",
//Param 3
t => t.Prop1,
t => t.Prop2,
t => t.Prop3
);
return tests.First();
}
}
Below is the actual test that MOQ fails with a "All invocations on the mock must have a corresponding setup." Can't see why on earth the setup wont be matched! any help would be appreciated.
[TestFixture]
public class ControllerTests
{
public MockRepository Repository { get; set; }
protected Mock<IContext> MockContext { get; set; }
public SomeController Controller;
public List<Test> Tests;
public Test Test;
[SetUp]
public void SetUp()
{
Test = new Test { Prop1 = "1", Prop2 = "2", Prop3 = "3" };
Tests = new List<Test> { Test };
Repository = new MockRepository(MockBehavior.Strict);
MockContext = Repository.Create<IContext>();
Controller = new SomeController { ServiceContext = MockContext.Object };
}
[TearDown]
public void TearDown()
{
Repository.VerifyAll();
}
[Test]
public void DetailProgramme_Test()
{
MockContext.Setup(m => m.Retrieve<Test>
(
//Param 1
It.IsAny<Expression<Func<Test, bool>>>(),
//Param 2
It.IsAny<string>(),
//Param 3
It.IsAny<Expression<Func<Test, object>>>()
)
).Returns(Tests.AsQueryable());
Test info = Controller.RetrieveSomeInformation();
//myMock.Setup(r => r.Find(It.IsAny<Expression<Func<Person, bool>>>())).Returns(new List<Person>() { new Person() }.AsQueryable());
Assert.IsTrue(info == Test);
}
}
I believe it is down to this in your Setup...
//Param 3
It.IsAny<Expression<Func<Test, object>>>()
Which does not match the params array. Try...
//Param 3
It.IsAny<Expression<Func<Test, object>>[]>()
You are setting up your Mock after you have derived an instance out of it. Once you gained an object, this will not be affected by any changes to the mock. example:
object instance = mock.Object; // this version wont include what you have configured in the setup
mock.Setup(...);
object instance2 = mock.Object; // get the latest version including whatever you have configured in the setup
a dity way to fix your code is to remove the instantiate statement from the Setup method and make your Controller lazy, like:
public SomeController Controller = new Lazy<SomeController>(() => new SomeController() { ServiceContext = MockContext.Object });
This way, as long as you consume your controller after setup for the first time, you will always work with the latest version.
Using Moq's It.IsAny<> without a .CallBack forces you to write code that's not covered by your test. Instead, it allows any query/expression at all to pass through, rendering your mock basically useless from a unit testing perspective.
The solution: You either need to use a Callback to test the expression OR you need to constrain your mock better. Either way is messy and difficult. I've dealt with this issue for as long as I've been practicing TDD. I finally threw together a helper class to make this a lot more expressive and less messy. Here's one possible end-result:
mockPeopleRepository
.Setup(x => x.Find(ThatHas.AnExpressionFor<Person>()
.ThatMatches(correctPerson)
.And().ThatDoesNotMatch(deletedPerson)
.Build()))
.Returns(_expectedListOfPeople);
Here's the blog article that talks about it and gives the source code: http://awkwardcoder.com/2013/04/24/constraining-mocks-with-expression-arguments/

Categories

Resources