Is it possible to return passed parameter to mocked method with fluent moq?
From:
mock.Setup(m => m.Foo(
It.IsAny<string>())).Returns<string>(s => s);
to:
Mock.Of<Bar>(m => m.Foo(It.IsAny<string>()) == ???);
Related
I have an abstract validator, with the following structure:
public abstract class RiskAssessmentServiceCreateRequestValidator<T>
: AbstractValidator<T> where T
: IRiskAssessmentServiceCreateRequest
{
public RiskAssessmentServiceCreateRequestValidator(ApplicationContext context)
{
RuleSet("modelBinding", () =>
{
RuleFor(x => x.ServiceProviderId).NotNull().GreaterThan(0);
});
RuleSet("handler", () =>
{
//....
});
}
}
In my request handler I am calling a derived instance of this class like that:
var validationResult = _validator.Validate(request, ruleSet: "handler");
How can I mock that particular call to Validate in my unit tests? If I would not use the rule sets, my Setup would look like this:
_validator.Setup(x => x.Validate(It.IsAny<CreateRequest>()))
.Returns(validationResult);
The following call is not allowed, since optional parameters are not allowed in an expression tree:
_validator.Setup(x => x.Validate(
It.IsAny<CreateRequest>(),
ruleSet: It.IsAny<string>()))
.Returns(validationResult);
Theoretically I could set it up like this:
_validator.Setup(x => x.Validate(
It.IsAny<CreateRequest>(),
(IValidatorSelector)null,
It.IsAny<string>()))
.Returns(validationResult);
But this then results in:
System.NotSupportedException : Unsupported expression: x => x.Validate<CreateRequest>(It.IsAny<CreateRequest>(), null, It.IsAny<string>())
Extension methods (here: DefaultValidatorExtensions.Validate) may not be used in setup / verification expressions.
Except from using the real validator, which I want to avoid, how can I resolve this and setup Moq in a suitable way?
There are really two questions here.
The first is how to mock with optional parameters - Simply treat optional parameters are non-optional.
However, you are trying to mock an extension method, that is not possible. Instead, you need to mock the method that the extension is trying to call. A cursory glance at the source, and I think that under the hood it is calling validator.Validate(ValidationContext) so your Moq code could be something like this:
_validator
.Setup(x => x.Validate(It.IsAny<ValidationContext<CreateRequest>>())
.Returns(validationResult);
Try
var mock = new Mock<AbstractValidator<object>>();
mock.Setup(x => x.Validate(It.Is<ValidationContext<object>>(ctx => IsExpectedRuleSet(ctx, new[] { "Rule1", "Rule2" }))))
.Return(...);
mock.Object.Validate(new object(), ruleSet: "Rule1,Rule2");
bool IsExpectedRuleSet(ValidationContext context, string[] expectedRuleSet)
{
return (context.Selector as FluentValidation.Internal.RulesetValidatorSelector)?.RuleSets.SequenceEqual(expectedRuleSet) == true;
}
I'm trying to map one complex object to another using instance API:
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Student, PersonType>();
cfg.CreateMap<Professor, PersonType>();
cfg.CreateMap<Branch, BranchType>()
.ForMember(x => x.Departments, opt => opt.MapFrom(src =>
new DepartmentType[] {
new DepartmentType
{
Students = Mapper.Map<Student[], PersonType[]> (src.Students),
Professors = Mapper.Map<Professor[], PersonType[]> (src.Professors),
Name = src.DepartmentName
}
}))
.ForMember(x => x.Name, opt => opt.MapFrom(src => src.Name))
.ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null));
});
var mapper = config.CreateMapper();
var test = mapper.Map<BranchType>(source);
The problem is I don't know how to achieve this without mixing instance and static API which is not working. Here is the error:
InvalidOperationException: Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance.
Apparently mixing of the static and instance based approaches is not allowed:
Students = Mapper.Map<Student[], PersonType[]> (src.Students)
How to use existing map to apply it to a property of the complex object with instance API?
I have this strange problem with MOQ and I cant use the GetAll('include') method to test my controller.
My Tests initialization
// GetAll
menusDb.Setup(m => m.GetAll()).Returns(menus.AsQueryable());
menusDb.Setup(m => m.GetAll(It.IsAny<Expression<Func<Menu, object>>>()))
.Returns((Expression<Func<Menu,object>> pred) => {
return menus.AsQueryable();
});
// FindByIdAsync
menusDb.Setup(m => m.FindByByIdAsync(It.IsAny<int>()))
.Returns((int x) => Task.FromResult(menus.Find(m => m.ID == x)));
menusDb.Setup(m => m.FindByByIdAsync(It.IsAny<int>(), It.IsAny<Expression<Func<Menu, object>>[]>()))
.Returns((int x, Expression<Func<Menu,
object>>[] includeProperties) => Task.FromResult(menus.Find(m => m.ID == x)));
Now whenever I am trying to test
_menusDB.GetAll(s=>s.Sections)
The moq version of menusdb.getAll() method is not fired at all
All other Moq methods are triggered correctly...
examples
_menusDB.GetAll();
_menusDB.FindByByIdAsync(id,
m => m.Sections.Select(s => s.Image),
m => m.Sections.Select(s => s.MenuItems.Select(mi => mi.Image)));
And these are the Getall and find functions with includes in my generic repository.
public IQueryable<TEntity> GetAll<TProperty>(Expression<Func<TEntity, TProperty>> propertyToInclude) {
return ObjectSet.Include(propertyToInclude);
}
public async Task<TEntity> FindByByIdAsync(int id, params Expression<Func<TEntity, object>>[] propertiesToInclude) {
var query = propertiesToInclude.Aggregate(ObjectSet as IQueryable<TEntity>, (current, property) => current.Include(property));
return await query.SingleOrDefaultAsync(entity => entity.ID == id).ConfigureAwait(false);
}
I finally found where is the problem. GetAll with include uses generic TProperty instead of object to include the properties. Mock cant somehow relate the object Tproperty with the linq query i provide in test. Maybe there is a way to make it work but for now i simply changed the generic property to object
Given the following code:
public static IMapper ConfigureMapper()
{
var config = new MapperConfiguration(cfg => {
cfg.ShouldMapField = fi => false;
cfg.ShouldMapProperty = pi => pi.GetMethod != null && (pi.GetMethod.IsPublic || pi.GetMethod.IsVirtual);
cfg.CreateMap<ServiceModel.Types.NonRiskRequirement, RequiredSignature>()
.ForMember(dest => dest.ApplicantFlag, opt => opt.MapFrom(src => src.RequiredSignatureApplicantFlag))
.ForMember(dest => dest.InsuredFlag, opt => opt.MapFrom(src => src.RequiredSignatureInsuredFlag));
cfg.CreateMap<ServiceModel.Types.NonRiskRequirement, NonRiskWorkItem>()
.ForMember(dest => dest.RequiredSignature, opt => opt.MapFrom(
src => Mapper.Map<ServiceModel.Types.NonRiskRequirement, RequiredSignature>(src)))
.ForMember(dest => dest.WorkType, opt => opt.MapFrom(src => src.WorkType));
});
config.AssertConfigurationIsValid();
return config.CreateMapper();
}
What is the proper syntax to get rid of the static "Mapper.Map"?, I'm using AutoMapper 5.1.1 with Autofac 4.1.1 and getting this exception back.
System.InvalidOperationException: Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance.
Thank you,
Stephen
Don't use MapFrom, use ResolveUsing. It gives you a ResolutionContext object that includes a Mapper property that you use to map, not this static way, which is not recommended, and also now broken.
I have the following method on my repository interface:
IQueryable<T> GetQuery<T>(Expression<Func<T, bool>> predicate) where T : class;
I have a class I'm going to act on in a unit test with the following constructor:
public MyClass(IUnitOfWork unitOfWork)
On IUnitOfWork Interface there is an exposed Repository property:
Repository Repository { get; }
So I'm trying to unit test the MyClass.DoSomething() method like so:
[TestInitialize]
public void Setup()
{
accounts = new List<Account>()
{
new Account()
{
Id = 123
}
};
}
Next I have the unit test Arrange section which is failing:
//Arrange
var repositoryMock = new Mock<IUnitOfWork>();
repositoryMock.Setup(x => x.Repository.GetQuery<Account>(y => y.Id == 123))
.Returns(accounts.AsQueryable()); //This setup always fails
var myClass = new MyClass(repositoryMock.Object); //don't even get here
The exception I get is:
System.NotSupportedException: Invalid setup on a non-virtual
(overridable in VB) member: x => x.Repository.GetQuery(y =>
y.Id == 123)
I've tried other variations of the Setup on the mock:
repositoryMock.Setup(x => x.Repository.GetQuery<Account>()).Returns((Account a) => accounts.AsQueryable().Where(z => z.Id == 123));
and
repositoryMock.Setup(x => x.Repository.GetQuery<Account>(y => y.Id == 123)).Returns((Account a) => accounts.AsQueryable().Where(z => z == a));
But to no success; I get the identical exception each time. They always throw the same exception when I run the unit test. Since I am using an Interface to be mocked, why am I getting this exception and how do I do this properly? Thanks!
Instead of your current setup try this:
//Arrange
var repositoryMock = new Mock<IUnitOfWork>();
repositoryMock.Setup(x => x.Repository.GetQuery<Account>(
It.IsAny<Expression<Func<T, bool>>>());
.Returns(accounts.AsQueryable()); // This should not fail any more
var myClass = new MyClass(repositoryMock.Object);
In reality, you do not need to pass any concrete lambda because you are returning your list either way.
The Repository property you have shown is not of an interface type. It's some concrete class. And as the error message tells you, you cannot define expectations on non virtual methods. So what you should do instead is to work with an abstraction if you want to be able to mock it:
IRepository Repository { get; }