I have the following interface
public interface ICommand<TResult, TModel>
{
Task<TResult> DoWorkAsync(TModel model);
}
Which is implemented by one or more such Command classes:
public class MyCommand1 : ICommand<Response, Model>()
{
public async Task<Response> DoWorkAsync(Model model) {
// do something
}
}
public class MyCommand2 : ICommand<Response, Model>()
{
public async Task<Response> DoWorkAsync(Model model) {
// do something else
}
}
The Respose and Model classes are as follows:
public class Response
{
public bool IsSuccessful {get;set;}
}
public class Model
{
public Guid Id {get;set;}
public string Name {get;set;}
}
Then I have an orchestrator class that has a dependency on an IEnumerable of IEnumerable<ICommand<Response, Model>>
public class MyOrchestrator
{
private readonly IEnumerable<ICommand<Response, Model>> _commands;
public MyOrchestrator(IEnumerable<ICommand<Response, Model>> commands)
{
_commands = commands;
}
public async Task ExecuteAsync(Model model)
{
myCommand1_Response = await _commands
.OfType<MyCommand1>()
.First()
.DoWorkAsync(model);
myCommand2_Response = await _commands
.OfType<MyCommand2>()
.First()
.DoWorkAsync(model);
// other operations
}
}
Now in my test I'm trying to mock the MyOrchestrator class's dependency IEnumerable<ICommand<Response, Model>> for each of the MyCommand types. How can I achieve this?
The problem is that MyCommand2 and MyCommand1 are concrete classes. You'll either need to make them be IMyCommand1 and IMyCommand2 or make DoWorkAsync virtual.
I think you could simplify your orchestator which would make mocking trivial.
public class MyOrchestrator
{
...
public MyOrchestrator(ICommand<Response, Model> command1, ICommand<Response, Model> command2)
{
this.command1 = command1 ?? throw...;
this.command2 = command2 ?? throw...;
}
public async Task ExecuteAsync(Model model)
{
myCommand1_Response = await command1.DoWorkAsync(model);
myCommand2_Response = await command1.DoWorkAsync(model);
// other operations
}
}
Now mocking this is nothing special.
var mockCommand1 = new Mock<ICommand<Response, Model>>(MockBehaviour.Strict);
...
var tested = new MyOrchestrator(command1: mockCommand1.Object, ...);
Related
I have created following abstraction for scheduling jobs:
public abstract class BaseJob
{
public string? JobId { get; set; }
}
public interface IJobData
{ }
public interface IJob<in TJobData> where TJobData : IJobData
{
Task ExecuteAsync(TJobData jobData);
}
I create jobs using a factory:
public class JobCreator<TJob, TJobData>
where TJob : IJob<TJobData>, new()
where TJobData : IJobData
{
public async Task ExecuteAsync(TJobData jobData)
{
var job = new TJob();
await job.ExecuteAsync(jobData);
}
}
Example implementation:
public record ForgotPasswordJobData() : IJobData;
public class ForgotPasswordJob: BaseJob, IJob<ForgotPasswordJobData>
{
private readonly IMailService _mailer;
public ForgotPasswordJob(IMailer mailer)
{
_mailer = mailer;
}
public Task ExecuteAsync(ForgotPasswordJobData jobData)
{
// Do something
// Send mail
}
}
This is how a job is enqueued:
JobClient.Enqueue<JobCreator<ForgotPasswordJob, ForgotPasswordJobData>>(job => job.ExecuteAsync(jobData));
Because ForgetPasswordJob does not have a parameterless constructor I get a CS0310 error which is saying
The type 'ForgotPasswordJob' must be a non-abstract type with a public
parameterless constructor in order to use it as parameter 'parameter'
in the generic type or method 'JobCreator<IJob,IJobData>'
How can I use dependencies in implementations of IJob?
You would need to tell your JobCreater how to instantiate the TJob:
public class JobCreator<TJob, TJobData>
where TJob : IJob<TJobData>
where TJobData : IJobData
{
public async Task ExecuteAsync(Func<TJob> createJob, TJobData jobData)
{
var job = createJob();
await job.ExecuteAsync(jobData);
}
}
var mailService = new MailService();
JobClient.Enqueue<JobCreator<ForgotPasswordJob, ForgotPasswordJobData>>(
job => job.ExecuteAsync(() => new ForgotPasswordJob(mailService), jobData));
Although I'm not sure JobCreator is really necessary
You could change your JobClient to accept an already instantiated job, considering that does not rely on anything within Enqueue:
void Enqueue<TJob, TJobData>(TJob job, TJobData jobData)
where TJob : IJob<TJobData>
where TJobData : IJobData
{
// ...
Task jobTask = job.ExecuteAsync(jobData);
// ...
}
var forgotPasswordJob = new ForgotPasswordJob(new MailService());
JobClient.Enqueue(forgotPasswordJob, jobData);
I have some codes like below, I want to write unit tests my method. But I'm stuck in async methods. Can you help me please ?
public class Panel
{
public int Id { get; set; }
[Required] public double Latitude { get; set; }
public double Longitude { get; set; }
[Required] public string Serial { get; set; }
public string Brand { get; set; }
}
public class CrossSolarDbContext : DbContext
{
public CrossSolarDbContext()
{
}
public CrossSolarDbContext(DbContextOptions<CrossSolarDbContext> options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
public interface IGenericRepository<T>
{
Task<T> GetAsync(string id);
IQueryable<T> Query();
Task InsertAsync(T entity);
Task UpdateAsync(T entity);
}
public abstract class GenericRepository<T> : IGenericRepository<T>
where T : class, new()
{
protected CrossSolarDbContext _dbContext { get; set; }
public async Task<T> GetAsync(string id)
{
return await _dbContext.FindAsync<T>(id);
}
public IQueryable<T> Query()
{
return _dbContext.Set<T>().AsQueryable();
}
public async Task InsertAsync(T entity)
{
_dbContext.Set<T>().Add(entity);
await _dbContext.SaveChangesAsync();
}
public async Task UpdateAsync(T entity)
{
_dbContext.Entry(entity).State = EntityState.Modified;
await _dbContext.SaveChangesAsync();
}
}
public interface IPanelRepository : IGenericRepository<Panel> { }
public class PanelRepository : GenericRepository<Panel>, IPanelRepository
{
public PanelRepository(CrossSolarDbContext dbContext)
{
_dbContext = dbContext;
}
}
[Route("[controller]")]
public class PanelController : Controller
{
private readonly IPanelRepository _panelRepository;
public PanelController(IPanelRepository panelRepository)
{
_panelRepository = panelRepository;
}
// GET panel/XXXX1111YYYY2222
[HttpGet("{panelId}")]
public async Task<IActionResult> Get([FromRoute] string panelId)
{
Panel panel = await _panelRepository.Query().FirstOrDefaultAsync(x => x.Serial.Equals(panelId, StringComparison.CurrentCultureIgnoreCase));
if (panel == null) return NotFound();
return Ok(panel);
}
}
public class PanelControllerTests
{
private readonly PanelController _panelController;
private static readonly Panel panel = new Panel { Id = 1, Brand = "Areva", Latitude = 12.345678, Longitude = 98.7655432, Serial = "AAAA1111BBBB2222" };
private readonly IQueryable<Panel> panels = new List<Panel>() { panel }.AsQueryable();
private readonly Mock<IPanelRepository> _panelRepositoryMock = new Mock<IPanelRepository>();
public PanelControllerTests()
{
_panelRepositoryMock.Setup(x => x.Query()).Returns(panels);
// I also tried this. I got another error 'Invalid setup on an extension method: x => x.FirstOrDefaultAsync<Panel>(It.IsAny<Expression<Func<Panel, Boolean>>>(), CancellationToken)'
// _panelRepositoryMock.As<IQueryable<Panel>>().Setup(x => x.FirstOrDefaultAsync(It.IsAny<Expression<Func<Panel, bool>>>(), default(CancellationToken))).ReturnsAsync(panel);
_panelController = new PanelController(_panelRepositoryMock.Object);
}
[Fact]
public async Task Register_ShouldInsertOneHourElectricity()
{
IActionResult result = await _panelController.Get("AAAA1111BBBB2222");
Assert.NotNull(result);
var createdResult = result as CreatedResult;
Assert.NotNull(createdResult);
Assert.Equal(201, createdResult.StatusCode);
}
}
I'm getting this error
The provider for the source IQueryable doesn't implement IAsyncQueryProvider. Only providers that implement IEntityQueryProvider can be used for Entity Framework asynchronous operations.
I think that I need to mock 'FirstOrDefaultAsync' but I'm not sure and I don't know how to do. I tried something, however it couldn't be compiled.
I get stuck on this issue today and this lib resolve it for me https://github.com/romantitov/MockQueryable completely, please refer:
Mocking Entity Framework Core operations such ToListAsync, FirstOrDefaultAsync etc.
//1 - create a List<T> with test items
var users = new List<UserEntity>()
{
new UserEntity{LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012")},
...
};
//2 - build mock by extension
var mock = users.AsQueryable().BuildMock();
//3 - setup the mock as Queryable for Moq
_userRepository.Setup(x => x.GetQueryable()).Returns(mock.Object);
//3 - setup the mock as Queryable for NSubstitute
_userRepository.GetQueryable().Returns(mock);
You could implement an AsyncEnumerable which can be used like this:
private readonly IQueryable<Panel> panels = new AsyncEnumerable(new List<Panel>()
{
panel
});
Here is the implementation of it:
public class AsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T>
{
public AsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable) { }
public AsyncEnumerable(Expression expression) : base(expression) { }
public IAsyncEnumerator<T> GetEnumerator()
{
return new AsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IQueryProvider IQueryable.Provider => new AsyncQueryProvider<T>(this);
}
The AsyncEnumerator class:
public class AsyncEnumerator<T> : IAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public AsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public void Dispose()
{
_inner.Dispose();
}
public T Current => _inner.Current;
public Task<bool> MoveNext(CancellationToken cancellationToken)
{
return Task.FromResult(_inner.MoveNext());
}
}
The AsyncQueryProvider class:
public class AsyncQueryProvider<TEntity> : IAsyncQueryProvider
{
private readonly IQueryProvider _inner;
internal AsyncQueryProvider(IQueryProvider inner)
{
_inner = inner;
}
public IQueryable CreateQuery(Expression expression)
{
return new AsyncEnumerable<TEntity>(expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new AsyncEnumerable<TElement>(expression);
}
public object Execute(Expression expression)
{
return _inner.Execute(expression);
}
public TResult Execute<TResult>(Expression expression)
{
return _inner.Execute<TResult>(expression);
}
public IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression)
{
return new AsyncEnumerable<TResult>(expression);
}
public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute<TResult>(expression));
}
}
This is because of your mocking approach; your mock provider just returns panels for Query, and panels is a simple object with LINQ-to-Objects exposing it as queryable:
private readonly IQueryable<Panel> panels = new List<Panel>() { panel }.AsQueryable();
Indeed, this does not implement IAsyncQueryProvider. If you can get hold of the regular query provider, you should be able to wrap that with a fake always-synchronous version to spoof it (just use return Task.FromResult(Execute(expression))), but frankly I'm not sure that this would be a useful test... at that point you're skipping so many of the important realities of async that it probably isn't worth it.
For issue in entity framework core ,use Moq.EntityFrameworkCore library and setup your dbset as below:
contextMock.Setup(x => x.entity).ReturnsDbSet(entityList);
I was facing the same issue and solved it that way:
Instead of having my method public async Task I switched it to public void and then resolved the asynchronous methods with .GetAwaiter() instead of await.
When querying for panel, removing the async in firstordefault.
Also remove the async from tolist when querying for analytics
This is my first question here and i'm not very familliar with the C# terminology, so if i get some terms or definitions mixed up i appologize in advance.
I have set up a generic EF data access layer;
public class BaseService<TObject> where TObject : class
{
private DbContext Context;
private static readonly Lazy<BaseService<TObject>> lazy = new Lazy<BaseService<TObject>>(() => new BaseService<TObject>());
public static BaseService<TObject> Instance => lazy.Value;
public BaseService()
{
Context = new evEntities();
}
public BaseService(DbContext context)
{
Context = context;
}
public ICollection<TObject> GetAll()
{
return Context.Set<TObject>().ToList();
}
public async Task<ICollection<TObject>> GetAllAsync()
{
return await Context.Set<TObject>().ToListAsync();
}
public TObject Get(int id)
{
return Context.Set<TObject>().Find(id);
}
}
Together with this;
public static class DA
{
public static DataAccess.Categories Categories => new DataAccess.Categories();
public static DataAccess.Tags Tags => new DataAccess.Tags();
public static DataAccess.Users Users => new DataAccess.Users();
}
public static class DA<T> where T : class
{
public static BaseService<T> Base => new BaseService<T>();
}
So in my Business Layer i can do this;
public class Categories
{
public Categories() { }
public ICollection<Database.Categories> GetAll()
{
return DA.Categories.GetAll().ToList();
}
public async Task<ICollection<Database.Categories>> GetAllAsync()
{
return await DA.Categories.GetAllAsync();
}
public Database.Categories Get(int id)
{
return DA.Categories.Get(id);
}
}
For clarity. My EF creates classes/entities like 'Database.Categories' and 'Database.Users' which i pass as 'TObject' to my BaseService to get a standard way of pulling data from my database for all my entities.
Now my question. In a similar way i want to create a generic Business Layer. Like;
public class BusinessLogicBase<TModel>
{
public ICollection<TDBModel> GetAll()
{
return null;
}
public async Task<ICollection<TDBModel>> GetAllAsync()
{
return await DA.Categories.GetAllAsync();
}
public TDBModel Get(int id)
{
return DA.Categories.Get(id);
}
}
I want to be able to call the DA with a TObject like Database.Categories but this has to be dynamic, based on the type passed to the BusinessLogicBase. So i want to do something like this (which doesn't work);
private ???? DetermineDatabaseModel()
{
switch(typeof(TModell))
{
case Models.Categories:
return Database.Categories;
case Models.Users:
return Database.Users;
}
}
So i can do this;
public ICollection<TDBModel> GetAll()
{
var databaseModel = DetermineDatabaseModel()
return DA<databaseModel>().GetAll();
}
I hope you understand my question and can help me.
Thnx!
Sorry for the long post, and for all you 9gaggers, here's a potato... No just kidding, this is serious.
Have you tried something like:
public class BusinessLogicBase<TDBModel> where TDBModel : class {
public ICollection<TDBModel> GetAll() {
return DA<TDBModel>.Base.GetAll();
}
}
UPDATE 1:
Maybe it would help You if you try to write it without generics first and then convert it into more general pattern using generics. There are some missteps that are easier to solve without generics.
Method public ICollection<TDBModel> GetAll() can't return ICollection<TDBModel> because type parameter TDBModel is not defined either in class signature or method signature. I makes more sense if you define it like this:
public class BusinessLogicBase<TModel>
{
public ICollection<TModel> GetAll()
{
return null;
}
}
UPDATE 2:
try this simple console app to demonstrate dynamic keyword and watch what is stored in variables categories and users.
UPDATE 3:
Based on fiddle - I've changed IBaseService<dynamic> to dynamic:
public class BL<TModel>
{
// This is what i want to make dynamic.
// how do i create a return type that i can use in DA<>..
private Type testDetermineDatabaseModel()
{
switch(typeof(TModel).Name){
case "Categories":
return typeof(Database.Categories);
case "Users":
return typeof(Database.Users);
}
return null;
}
public ICollection<TModel> testGetAll()
{
var databaseModel = testDetermineDatabaseModel();
// return DA<databaseModel>().Base.GetAll();
return new List<TModel>();
}
// NEW
// I have constructed the following.
private dynamic baseService;
public dynamic DetermineDatabaseModel()
{
switch (typeof(TModel).Name)
{
case "Categories":
return new BaseService<Database.Categories>();
case "Users":
return new BaseService<Database.Users>();
default:
return null;
}
}
private IBaseService<TDbModel> GetBase<TDbModel>() where TDbModel : class
{
return new BaseService<TDbModel>();
}
public ICollection<TModel> GetAll()
{
ICollection<TModel> returnValue = new List<TModel>();
// This works!!!
foreach (var item in GetBase<Database.Categories>().GetAll())
{
returnValue.Add((TModel)(object)item);
}
baseService = DetermineDatabaseModel();
// This doesn't!!! It's the same thing!! :(
foreach (var item in baseService.GetAll())
{
returnValue.Add((TModel)(object)item);
}
return returnValue;
}
}
But remember, this not solve the issue You are facing. That is map 2 generic types.
Let's assume I have a class like
public class DataService
{
public IList<T> All<T>() { ... }
public T Get<T>(int id) { ... }
...
}
I could use it in various ways...
var dataService = new DataService();
var customers = dataService.All<Customer>();
var order = dataService.Get<Order>(1);
... but if I had a bunch of operations with the same T, this would become cumbersome. Then it would be nice to have something like this:
dataService.TypeIs<Order>();
var order2 = dataService.Get(2);
var order2 = dataService.Get(3);
var allOrders = dataService.All();
How would a TypeIs<T>() method look like? I think it had to somehow convert DataService to DataService<T> and set T... Or is this utterly impossible?
Yes, it's possible using a clever proxy:
public class DataService
{
public IList<T> All<T>() { ... }
public T Get<T>(int id) { ... }
...
}
public class DataServiceProxy<T>
{
public DataServiceProxy(DataService ds)
{
this.ds = ds;
}
public IList<T> All()
{
return this.ds.All<T>();
}
public T Get(int id)
{
return this.ds.Get<T>(id);
}
}
The equivalent of your dataService.TypeIs<Order>(); is var dataServiceProxy = new DataServiceProxy<Order>(dataService).
I have the below method:
public void Enqueue(ICommand itemToQueue)
{
if (itemToQueue == null)
{
throw new ArgumentNullException("itemToQueue");
}
// Using the dynamic keywork to ensure the type passed in to the generic
// method is the implementation type; not the interface.
QueueStorage.AddToQueue((dynamic)itemToQueue);
}
With QueueStorage being a dependency that implements IQueueStorage. I wish to unit test it but the (dynamic) keyword seems to be blocking Moq from binding correctly to it. The keyword is used to correctly assign the concrete class type rather than ICommand interface type when it is added to the queue.
The unit test looks like this:
[Test]
public void Enqueue_ItemGiven_AddToQueueCalledOnQueueStorage()
{
int timesAddToQueueCalled = 0;
var dummyQueueStorage = new Mock<IQueueStorage>();
var testCommand = new TestCommand();
var queueManager = new AzureCommandQueueManager();
dummyQueueStorage
.Setup(x => x.AddToQueue(It.IsAny<TestCommand>()))
.Callback(() => timesAddToQueueCalled++);
queueManager.QueueStorage = dummyQueueStorage.Object;
queueManager.Enqueue(testCommand);
Assert.AreEqual(1, timesAddToQueueCalled);
}
Whilst test command is a blank implementation of ICommand:
private class TestCommand : ICommand
{
}
public interface ICommand
{
}
The timesAddedToQueuCalled is not being incremented. I've tried using It.IsAny<ICommand> and (testCommand) to no avail. It looks like the Callback method is not being executed. Can anyone see what I'm doing wrong?
EDIT: IQueueStorage code:
public interface IQueueStorage
{
void AddToQueue<T>(T item) where T : class;
T ReadFromQueue<T>() where T : class;
}
Here is code which works without problems:
public class AzureCommandQueueManager
{
public void Enqueue(ICommand itemToQueue)
{
if (itemToQueue == null)
throw new ArgumentNullException("itemToQueue");
QueueStorage.AddToQueue((dynamic)itemToQueue);
}
public IQueueStorage QueueStorage { get; set; }
}
public interface IQueueStorage
{
void AddToQueue<T>(T command) where T : class;
}
public class TestCommand : ICommand {}
public interface ICommand {}
And test method:
[Test]
public void Enqueue_ItemGiven_AddToQueueCalledOnQueueStorage()
{
int timesAddToQueueCalled = 0;
var dummyQueueStorage = new Mock<IQueueStorage>();
var testCommand = new TestCommand();
var queueManager = new AzureCommandQueueManager();
dummyQueueStorage
.Setup(x => x.AddToQueue(It.IsAny<TestCommand>()))
.Callback(() => timesAddToQueueCalled++);
queueManager.QueueStorage = dummyQueueStorage.Object;
queueManager.Enqueue(testCommand);
Assert.AreEqual(1, timesAddToQueueCalled);
}
The only difference I see - you have private modifier of TestCommand class. Btw if it is private, how do you access that class from your tests?