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;
}
Related
In my .Net6 web app, I attempted to register service injection for 2 implementations of a single IWordRepository Interface:
WordRepositoryInMemory, working with in-memory data;
WordRepositoryDatabase with calls to the database;
Following the example set out in this article, I created an enum:
public enum WordRepositoryImplementation
{
WordRepositoryInMemory,
WordRepositoryDatabase
}
Then, in my Program.cs, I registered the two services:
builder.Services.AddScoped<WordRepositoryDatabase>();
builder.Services.AddScoped<WordRepositoryInMemory>();
builder.Services.AddTransient<Func<WordRepositoryImplementation, IWordRepository?>>(wordRepositoryProvider => key =>
{
return key switch
{
WordRepositoryImplementation.WordRepositoryInMemory => wordRepositoryProvider.GetService<WordRepositoryInMemory>(),
WordRepositoryImplementation.WordRepositoryDatabase => wordRepositoryProvider.GetService<WordRepositoryDatabase>(),
_ => null,
};
});
Then, I called it in my controller like so:
private readonly IWordRepository _wordRepositoryDatabase; // I only require one of the implementations to be called by this controller.
public DictionaryDataController(Func<WordRepositoryImplementation, IWordRepository> serviceResolver)
{
_wordRepositoryDatabase = serviceResolver(WordRepositoryImplementation.WordRepositoryDatabase);
}
Unfortunately, this added complexity messed up my tests for the controller. I am no longer able to instantiate the sut with a simple Mock.Object of the WordRepositoryDatabase service. By saying unable, I mean that I don't quite have the required experience handling delegates, yet.
In my test fixture, I tried to replace the original mock implementation of the service:
private Mock<IWordRepository> _wordRepository;
// ....
_wordRepository= new Mock<IWordRepository>();
// ....
DictionaryDataController sut = new(_wordRepositoryDatabase.Object);
To something that returns a Mock of the IWordRepository, so that I could use it in my constructor:
private Func<WordRepositoryImplementation, IWordRepository?> _funcWordRepositoryImplementation;
// ...
// ...
DictionaryDataController sut = new(_funcWordRepositoryImplementation);
However, I cannot grasp the required syntax here. The closest I got to was a parameterless Func<>() that returned the Mock.Object, but it was clearly missing something.
_funcWordRepositoryImplementation= () =>
{
return new Mock<WordRepositoryImplementation, IWordRepository>();
};
And attempts to pass some arguments to it caused their own set of errors.
What would the correct way to set up this field be?
Just use lambda expression with discard parameter which will return _wordRepositoryDatabase.Object:
DictionaryDataController sut = new(_ => _wordRepositoryDatabase.Object);
I'm mocking some implementation using Moq and I want verify a method is called correctly on this interface, the problem is it looks something like this:
public interface IToBeMocked {
void DoThing(IParameter parameter);
}
public interface IParameter {
Task<string> Content { get; }
}
So I set up my mock:
var parameter = "ABC";
var mock = new Mock<IToBeMocked>();
mock
.Setup(m => m.DoThing(It.IsAny<IParameter>()))
.Callback<IParameter>(p async => (await p.Content).Should().Be(parameter));
new Processor(mock.Object).Process(parameter);
mock
.Verify(m => m.DoThing(It.IsAny<IParameter>()), Times.Once);
Unfortunately, this test already passes with the following implementation:
public class Processor {
public Processor(IToBeMocked toBeMocked){
_toBeMocked = toBeMocked;
}
public void Process(string parameter){
_toBeMocked.DoThing(null);
}
}
Because the Callback is async but the signature requires an Action, meaning the awaiter is never awaited, and the test ends before the exception is thrown.
Is there any functionality in Moq to await an asynchronous callback?
Edit
There seems to be some confusion. I hope this clarifies the problem.
I'm doing TDD. I've implemented the simplest shell of the code to make the test compile. Then I have written the test to ensure "ABC" is the result of the Task and I've set the test running. It's passing. This is the issue. I want the test to fail, so I can implement the 'real' implementation.
Edit 2
The more I think about this the more I think this is probably impossible. I've opened an issue for the repo: https://github.com/moq/moq4/issues/737 but I was thinking about the implementation of such a feature as I was writing the request in anticipation of submitting a PR, and it seems impossible. Still if anyone has any ideas I'd love to hear them either here or in the GitHub issue and I'll keep both places up to date. For now, I suppose I will have to use a stub.
The call back expects an Action, you attempt to perform an async operation in said callback which boils down to async void call. Exceptions cannot be caught in such situations as they are fire and forget.
Reference Async/Await - Best Practices in Asynchronous Programming
So the problem is not with the Moq framework but rather the approach taken.
Use the call back to get the desired parameter and work from there.
Review the progression of the following tests to see how the TDD approach evolves with each test.
[TestClass]
public class MyTestClass {
[Test]
public void _DoThing_Should_Be_Invoked() {
//Arrange
var parameter = "ABC";
var mock = new Mock<IToBeMocked>();
mock
.Setup(m => m.DoThing(It.IsAny<IParameter>()));
//Act
new Processor(mock.Object).Process(parameter);
//Assert
mock.Verify(m => m.DoThing(It.IsAny<IParameter>()), Times.Once);
}
[Test]
public void _Parameter_Should_Not_Be_Null() {
//Arrange
IParameter actual = null;
var parameter = "ABC";
var mock = new Mock<IToBeMocked>();
mock
.Setup(m => m.DoThing(It.IsAny<IParameter>()))
.Callback<IParameter>(p => actual = p);
//Act
new Processor(mock.Object).Process(parameter);
//Assert
actual.Should().NotBeNull();
mock.Verify(m => m.DoThing(It.IsAny<IParameter>()), Times.Once);
}
[Test]
public async Task _Parameter_Content_Should_Be_Expected() {
//Arrange
IParameter parameter = null;
var expected = "ABC";
var mock = new Mock<IToBeMocked>();
mock
.Setup(m => m.DoThing(It.IsAny<IParameter>()))
.Callback<IParameter>(p => parameter = p);
new Processor(mock.Object).Process(expected);
parameter.Should().NotBeNull();
//Act
var actual = await parameter.Content;
//Assert
actual.Should().Be(expected);
mock.Verify(m => m.DoThing(It.IsAny<IParameter>()), Times.Once);
}
}
It MAY or MAY NOT actually work if you use an async method signature on the callback. Depends if your runtime decides to continue with the same thread or spin up a new one.
If it makes sense, and it often does, to do some Asserts or grab some parameters for later validation in the Callback, you should remove the async stuff all together and force it to run via
Task.Run(() => AsyncMethodHere).Result
I've got a class and a method that looks something like this:
public class FieldLookup : IFieldLookup
{
public string LookupField(string Var1, string Var2)
{
// do a database lookup
}
}
This works fine in the actual class where it's being used with Dependency Injection. What I'm trying to figure out is how, in the Unit Test, do I use the Moq framework to mock a call to this method.
var fieldLookup = new Mock<IFieldLookup>();
Then, how do I do this....?
fieldLookup.Setup<string>(x => x.LookupField("", "").Returns("something"));
fieldLookup.Setup(x => x.LookupField("", "").Returns("something"));
Both of these tell me that "String does not contain a definition for Return". Been playing around, but not getting it.
You put parentheses on the wrong place, you need to call the Returns method on the object returned by the Setup method.
fieldLookup.Setup<string>(x => x.LookupField("", "")).Returns("something");
fieldLookup.Setup(x => x.LookupField("", "")).Returns("something");
I have to test a projection that handle a given events and persist it on a read only Mongo database (I'm using official c# Mongo Driver):
public class MyObjectProjection : IHandleMessages<RegisteredEvent>
{
private MongoCollection<MyObjectView> _collection;
private MyObjectView item;
public MyObjectProjection (MongoDatabase db)
{
_collection = db.GetCollection<MyObjectView>("my-object");
}
public void Handle(RegisteredEvent message)
{
item = new MyObjectView();
item.Id = message.Id;
// some code omitted
_collection.Save(item);
}
}
I need to unit test the Handle method, given that:
I don't want an integration test. Database and collection are mocked, so the save is not real
I just want to test the item-message mapping
the members are hidden and I don't want to make them more visibile
Should I use alternative solution rather than reflection or friendly assembly? What is the best practice in a case like this?
Right now my test look like this:
[TestMethod]
public void TestMethod1()
{
// ARRANGE - some code omitted
databaseMock
.Setup(x => x.GetCollection<MyObjectView>(It.IsAny<string>()))
.Returns(collection);
collectionMock
.Setup(x => x.Save(It.IsAny<MyObjectView>()))
.Returns(It.IsAny<WriteConcernResult>);
// ACT
var handler = new MyObjectProjection(database);
handler.Handle(evt);
// ASSERT
// nothin' to assert here!
}
this works, but i have nothing to assert when Handle method is completed.
What is the best practice in a case like this?
The best practice is to make members visible. Is there any particular reason why you need to hide members?
Then, you can assert against argument passed to Save method :
MyObjectView objectView;
collectionMock
.Setup(x => x.Save(It.IsAny<MyObjectView>()))
.Callback<MyObjectView>((obj) => objectView= obj)
.Returns(It.IsAny<WriteConcernResult>);
Assert.That(objectView.Id, Is.EqualTo(evt.Id));
//assert other properties
Well, your Handle() method interacts with the collection, by calling the Save() method. Therefore you can expect that the element passed to the Handle method has proper ID set:
collectionMock.Verify(x=>x.Save(It.Is<MyObjectView>(v => v.Id == 5)), Times.Once,"save should be called with object with Id = 5");
I assumed here that the evt that is passed into Handle() has and Id of 5. Code not tested, but I think something like that would do the trick.
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; }