How to Mock or Fake MongoDB 's static method FindAsync() in .Net Unit test cases using MOQ or FakeItEasy or Pose - mongodb

I have been trying to mock/fake the static method FindAsync() in my Unit test cases using Wrappers, some concepts of Pose.
As the static methods cannot be mocked or faked normally.
It is not successful.
The code in the repository layer which I want to unit test points to the IMongoCollectionExtension.FindAsync() method.
This is the method I am trying to mock
public async Task<MyClass> GetItem(Guid id)
{
var filter = Builders<MyClass>.Filter.Eq(m => m.Id, id);
var result = await _context.MyCollection.FindAsync(filter);
return result.FirstOrDefault();
}
This FindAsync() is pointing to IMongoCollectionExtensions STATIC class
public static Task<IAsyncCursor<TDocument>> FindAsync<TDocument>(this IMongoCollection<TDocument> collection, FilterDefinition<TDocument> filter, FindOptions<TDocument, TDocument> options = null, CancellationToken cancellationToken = default(CancellationToken));
So as it is pointing to Static class and a static method I started writing wrapper to mock,
First Method tried using Wrapper:
This is wrapper I have created.
public interface IMongoCollectionExtensionsWrapper
{
Task<IAsyncCursor<MyClass>> FindAsync<MyClass>(IMongoCollection<MyClass> collection, FilterDefinition<MyClass> filter, FindOptions<MyClass, MyClass> options = null, CancellationToken cancellationToken = default(CancellationToken));
}
public class MongoCollectionExtensionsWrapper : IMongoCollectionExtensionsWrapper
{
public Task<IAsyncCursor<MyClass>> FindAsync<MyClass>(IMongoCollection<MyClass> collection, FilterDefinition<MyClass> filter, FindOptions<MyClass, MyClass> options = null, CancellationToken cancellationToken = default(CancellationToken))
{
return collection.FindAsync(filter, options, cancellationToken);
}
}
public static class FakeExtensions
{
public static IMongoCollectionExtensionsWrapper defaultmcExtWrapper = new MongoCollectionExtensionsWrapper();
public static Task<IAsyncCursor<MyClass>> FindAsync(this IMongoCollection<MyClass> collection, FilterDefinition<MyClass> filter, FindOptions<MyClass, MyClass> options = null, CancellationToken cancellationToken = default(CancellationToken))
{
return defaultmcExtWrapper.FindAsync(collection, filter, options, cancellationToken);
}
}
As the wrapper was not working properly i checked out free framework Pose to mock static methods. That was not successful too.
Second trial using Pose
Shim findshim = Shim.Replace(() => IMongoCollectionExtensions.FindAsync(Is.A<IMongoCollection<MyClass>>(), filter, null, CancellationToken.None)).With(delegate (IMongoCollection<MyClass> mc, FilterDefinition<MyClass> f, FindOptions<MyClass, MyClass> o, CancellationToken ca) { return Task.FromResult(_fakeOutput.FakedObject); });
NOTE: _fakeOutput is a faked Cursor holding an IEnumerable. It works fine.
PoseContext.Isolate(() =>
{
Task.Run(() =>
{
var exp = Task.FromResult(item1);
var myres = _Repo.GetItem(Id);
Assert.Equal(exp, myres);
});
}, findshim);
var myres = _Repo.GetItem(Id);
In both the trials, I have tried mocking IMongoCollectionExtensions.FindAsync() but result (output of the method i want to unit test after setting up mock/fake) in both cases are null
and when I tried below Assertion if the FindAsync() method of IMongoCollectionExtension has Happened or not, but it didn't hit. I dont understand when the method i want to unit test is pointing to IMongoCollectionExtension.FindAsync() only but it is not hitting.
fakeIMongoCollExt.CallsTo(x => x.FindAsync(A<IMongoCollection<MyClass>>.Ignored, A<FilterDefinition<MyClass>>.Ignored, null, CancellationToken.None)).MustHaveHappened();
(Method signature has MongoCollections as first parameter - Extension Method)
is showing that it didn't hit that method.
So I tried checking MustHaveHappened() for IMongoCollection.FindAsync() (It is interface method not the static class method which we are discussing above) which also tells that "The target of this call is not the fake object being configured."
I am not sure how FindAsync() is pointing. How to proceed with unit test cases. Please let me know if you have any idea.. Thanks in Advance..
IMongoCollections.FindAsync() Mocking

Related

How to update shadow properties with Entity Framework Core ExecuteUpdate method?

On saving changes to the database, we want to update our shadow properties (CreatedOn & ModifiedOn) automatically. This can be done by using overriding SaveChangesAsync method in the DbContext class.
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
ChangeTracker.DetectChanges();
var timestamp = systemClock.UtcNow.DateTime;
foreach (var entry in ChangeTracker.Entries()
.Where(e => e.Entity is BaseIdentifierEntity)
.Where(e => e.State == EntityState.Added || e.State == EntityState.Modified))
{
if (entry.State == EntityState.Added)
{
entry.Property(nameof(BaseIdentifierEntity.CreatedOn)).CurrentValue = timestamp;
}
if (entry.State == EntityState.Modified)
{
entry.Property(nameof(BaseIdentifierEntity.ModifiedOn)).CurrentValue = timestamp;
}
};
return base.SaveChangesAsync(cancellationToken);
}
Now we want to use the ExecuteUpdateAsync EF code method to update records in bulk but those changes are not detected by the change tracker.
Eg.
await context.Invoices
.Where(_ => _.Status == InvoiceStatusEnum.Draft)
.ExecuteUpdateAsync(_ => _.SetProperty(invoice => invoice.Status, InvoiceStatusEnum.Approved), cancellationToken);
One possible solution we're thinking about, is having a ExecuteUpdateWithShadowPropertiesAsync method but we don't succeed to merge the 2 expressions into one.
public static class EntityFrameworkExtensions
{
public static Task<int> ExecuteUpdateWithShadowPropertiesAsync<TSource>(this IQueryable<TSource> source, Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> setPropertyCalls, CancellationToken cancellationToken = default) where TSource : BaseIdentifierEntity
{
Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> setShadowPropertyCalls = _ => _.SetProperty(p => p.ModifiedOn, DateTime.UtcNow);
// TODO: A method to combine both expressions into one expression
var mergedPropertyCalls = Merge(setPropertyCalls, setShadowPropertyCalls);
return source.ExecuteUpdateAsync(mergedPropertyCalls, cancellationToken: cancellationToken);
}
}
Actually there are two or three questions here, so let handle them separately.
How to update shadow properties with Entity Framework Core ExecuteUpdate method?
Shadow properties inside any EF Core query expression tree are accessed through EF.Property method, which is EF Core generic property accessor expression and works for both shadow and regular properties.
So if your ModifiedOn was a shadow property (it isn't) of type DateTime, it can be updated as follows:
query.ExecuteUpdateAsync(s => s
.SetProperty(p => EF.Property<DateTime>("ModifiedOn"), DateTime.UtcNow)
...);
How to combine lambda expressions?
This has been covered by many answers on SO, or over internet. But basically you need to emulate "call" to one of the expressions passing the other as argument. This is achieved with either Expression.Invoke which is not always supported by query translators (including EF Core), or (which always works) by replacing the parameter of the "called" lambda expression with the body of the other lambda expression.
The later is achieved with custom ExpressionVisitor. You can find many implementations, EF Core also provides its own called ParameterReplacingVisitor, but I'm using my own little expression helper class, which is general and have no EF Core or other 3rd party dependencies. It is quite simple:
namespace System.Linq.Expressions;
public static class ExpressionUtils
{
public static Expression ReplaceBodyParameter<T, TResult>(this Expression<Func<T, TResult>> source, Expression value)
=> source.Body.ReplaceParameter(source.Parameters[0], value);
public static Expression ReplaceParameter(this Expression source, ParameterExpression target, Expression replacement)
=> new ParameterReplacer(target, replacement).Visit(source);
class ParameterReplacer : ExpressionVisitor
{
readonly ParameterExpression target;
readonly Expression replacement;
public ParameterReplacer(ParameterExpression target, Expression replacement)
=> (this.target, this.replacement) = (target, replacement);
protected override Expression VisitParameter(ParameterExpression node)
=> node == target ? replacement : node;
}
}
With that helper, the method you are looking for would be:
// TODO: A method to combine both expressions into one expression
var mergedPropertyCalls = Expression.Lambda<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>>(
setShadowPropertyCalls.ReplaceBodyParameter(setPropertyCalls.Body),
setPropertyCalls.Parameters);
You can go further and add a shortcut helper method specific for SetPropertyCalls:
public static Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> Append<TSource>(
this Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> target,
Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> source)
where TSource : class
=> Expression.Lambda<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>>(
source.ReplaceBodyParameter(target.Body), target.Parameters);
and then the generic method in question would be simply:
public static Task<int> ExecuteUpdateWithShadowPropertiesAsync<TSource>(
this IQueryable<TSource> source,
Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> setPropertyCalls,
CancellationToken cancellationToken = default)
where TSource : BaseIdentifierEntity
=> source.ExecuteUpdateAsync(setPropertyCalls
.Append(s => s.SetProperty(p => p.ModifiedOn, DateTime.Now)),
cancellationToken);
Now having the previous two questions answered, the next would be - Instead of using custom extension method, can this be done better in EF Core? Ideally on a similar fashion as the change tracker (SaveChanges) approach.
And the answer is yes. EF Core 7.0 along with batch updates introduced a long asked and very handy feature called Interception to modify the LINQ expression tree (unfortunately not documented yet). It allows you to intercept and modify LINQ query expression tree before EF Core. In this case, it could be used to add more update properties to ExecuteUpdate query.
In order to utilize it, we first define interceptor class
#nullable disable
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Query;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace Microsoft.EntityFrameworkCore;
internal class ExecuteUpdateInterceptor : IQueryExpressionInterceptor
{
List<(Type Type, Delegate Calls, Func<IEntityType, bool> Filter)> items = new();
public ExecuteUpdateInterceptor Add<TSource>(
Func<Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>>> source,
Func<IEntityType, bool> filter = null)
{
items.Add((typeof(TSource), source, filter));
return this;
}
Expression IQueryExpressionInterceptor.QueryCompilationStarting(
Expression queryExpression, QueryExpressionEventData eventData)
{
if (queryExpression is MethodCallExpression call &&
call.Method.DeclaringType == typeof(RelationalQueryableExtensions) &&
call.Method.Name == nameof(RelationalQueryableExtensions.ExecuteUpdate))
{
var setPropertyCalls = (LambdaExpression)((UnaryExpression)call.Arguments[1]).Operand;
var body = setPropertyCalls.Body;
var parameter = setPropertyCalls.Parameters[0];
var targetType = eventData.Context?.Model.FindEntityType(parameter.Type.GetGenericArguments()[0]);
if (targetType != null)
{
foreach (var item in items)
{
if (!item.Type.IsAssignableFrom(targetType.ClrType)) continue;
if (item.Filter != null && !item.Filter(targetType)) continue;
var calls = (LambdaExpression)item.Calls.Method.GetGenericMethodDefinition()
.MakeGenericMethod(targetType.ClrType)
.Invoke(null, null);
body = calls.Body.ReplaceParameter(calls.Parameters[0], body);
}
if (body != setPropertyCalls.Body)
return call.Update(call.Object, new[] { call.Arguments[0], Expression.Lambda(body, parameter) });
}
}
return queryExpression;
}
}
This requires a bit more knowledge of expressions, so you can just use it as is. Basically what it does is intercepting the ExecuteUpdate "calls" and appending additional SetProperty "calls" based on statically configured rules and filters.
The only remaining is to create, configure and add the interceptor inside your OnConfigure override:
optionsBuilder.AddInterceptors(new ExecuteUpdateInterceptor()
//.Add(...)
//.Add(...)
);
The configuration is based on delegates, with only limitation/requirement the SetPropertyCalls generic Func to be a real generic method and not anonymous delegate (I haven't found a way to make it easy for use and at the same time being anonymous).
So here are some usages:
property of a base class (your case):
optionsBuilder.AddInterceptors(new ExecuteUpdateInterceptor()
.Add(SetModifiedOn<BaseIdentifierEntity>)
);
static Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> SetModifiedOn<TSource>()
where TSource : BaseIdentifierEntity
=> s => s.SetProperty(p => p.ModifiedOn, DateTime.UtcNow);
entity property with specific name and type (shadow or regular). Uses presence of the property as a filter. Also works in your case.
const string ModifiedOn = nameof(ModifiedOn);
optionsBuilder.AddInterceptors(new ExecuteUpdateInterceptor()
.Add(SetModifiedOn<object>, t => t.FindProperty(ModifiedOn) is { } p && p.ClrType == typeof(DateTime))
);
static Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> SetModifiedOn<TSource>()
where TSource : class
=> s => s.SetProperty(p => EF.Property<DateTime>(p,ModifiedOn), DateTime.UtcNow);
Note: The SetPropertyCalls func must be generic, to allow binding it to the actual source type from the query.
Also, I haven't mentioned it explicitly till now, but with the last approach, you just use a standard ExecuteUpdate or ExecuteUpdateAsync methods, and the interceptor adds the cofigured additional SetProperty expressions.
The following extension updates shadow property with other fields:
public static class EntityFrameworkExtensions
{
public static Task<int> ExecuteUpdateWithShadowPropertiesAsync<TSource>(this IQueryable<TSource> source,
Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> setPropertyCalls,
CancellationToken cancellationToken = default)
where TSource : class
{
Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> setShadowPropertyCalls =
x => x.SetProperty(p => EF.Property<DateTime>(p, "ModifiedOn"), p => DateTime.UtcNow);
var mergedPropertyCalls = Merge(setPropertyCalls, setShadowPropertyCalls);
return source.ExecuteUpdateAsync(mergedPropertyCalls, cancellationToken: cancellationToken);
}
static Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> Merge<TSource>(
Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> setPropertyCalls,
Expression<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>> additional)
{
var newBody = ReplacingExpressionVisitor.Replace(additional.Parameters[0], setPropertyCalls.Body, additional.Body);
return Expression.Lambda<Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>>>(newBody,
setPropertyCalls.Parameters);
}
}

EF 7 - Context returns null although values are there

I have a CQRS setup and I am trying to use domain events.
After I receive a command for a new order, I am adding the newly created Order object to the dbcontext.
public async Task<Guid> Handle(CreateOrderCommand message, CancellationToken cancellationToken)
{
...
var order = new Order(...);
...
order.SubmitOrder();
_orderRepository.Add(order);
await _orderRepository.UnitOfWork
.SaveEntitiesAsync(cancellationToken);
return order.Id;
}
The order.SubmitOrder() method is as follows
public void SubmitOrder()
{
AddDomainEvent(new OrderPlacedDomainEvent(Guid.NewGuid(), Id));
}
and orderRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken); is on overload to the UnitOfWork.SaveEntitiesAsync() as follows:
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default)
{
// Dispatch Domain Events collection.
// Choices:
// A) Right BEFORE committing data (EF SaveChanges) into the DB will make a single transaction including
// side effects from the domain event handlers which are using the same DbContext with "InstancePerLifetimeScope" or "scoped" lifetime
// B) Right AFTER committing data (EF SaveChanges) into the DB will make multiple transactions.
// You will need to handle eventual consistency and compensatory actions in case of failures in any of the Handlers.
if (_mediator != null)
{
await _mediator.DispatchDomainEventsAsync(this);
}
// After executing this line all the changes (from the Command Handler and Domain Event Handlers)
// performed through the DbContext will be committed
await base.SaveChangesAsync(cancellationToken);
return true;
}
Note that the changes are not saved before the events are dispatched and the handler is called.
Now in the event handler when I am trying to get the order object from the context:
await _context.Orders.Include(o => o.OrderItems).SingleOrDefaultAsync(o => o.Id == id, cancellationToken: cancellationToken);
it returns null although the data is available in the context under _context.ChangeTracker.DebugView.LongView
Is there any way to get the order data here?
Well, solution found:
If Find/FindAsyncis used instead of SingleOrDefaultAsync it will return the values available in the change tracker.
public async Task<Order?> FindAsync(Guid id, CancellationToken cancellationToken = default)
=> await _context.Orders.FindAsync(new object[] { id }, cancellationToken: cancellationToken);

Re-using reference to an IReliableCollection

Is it acceptable to re-use a reference to a IReliableCollection or should I request from IReliableStateManager every time I want to use it?
For example, if I have a dictionary that is widely used in my application, is it acceptable to retrieve it once in the RunAsync method and then pass this reference to any method that requires it, e.g:
protected override async Task RunAsync(CancellationToken cancellationToken)
{
_someCollection = StateManager.GetOrAddAsync<IReliableDictionary<int, string>>(
"SomeName");
}
public async Task DoSomething(int id, string message)
{
_someClass.DoSomething(_someCollection, id, message);
}
And then use in a class like so:
public class SomeClass
{
public void DoSomething(IReliableDictionary<int, string> dict, int id, string msg)
{
using (ITransaction tx = StateManager.CreateTransaction())
{
await dict.AddAsync(tx, id, msg);
await tx.CommitAsync();
}
}
}
Or should I request from IReliableStateManager on each call, e.g,
public class SomeClass
{
public void DoSomething(int id, string msg)
{
var dict = StateManager.GetOrAddAsync<IReliableDictionary<int, string>>("SomeName");
using (ITransaction tx = StateManager.CreateTransaction())
{
await dict.AddAsync(tx, id, msg);
await tx.CommitAsync();
}
}
}
Passing a reference seems to work fine from what I can tell but I'm not sure whether this would be considered bad practice and I can't find a definitive answer in the guidelines or documentation
Yes. You can.
You can check this to see how you can even receive notifications when new instance of IReliableState is added to ReliableStateManager.
You can also subscribe for events (if this is a dictionary).

How to mock Entity Framework in a N-Layer Architecture

I have a N-Layer application with Entity Framework (Code-First approach). Now I want to automatize some tests. I am using Moq framework. I am finding some problem about writing the tests. Perhaps my architecture is wrong? With wrong, I mean that I wrote components that are not well isolated and so they are not testable. I do not really like this... Or perhaps, I simply cannot use correctly moq framework.
I let you see my architecture:
At every level I inject my context in the constructor of the class.
The Facade:
public class PublicAreaFacade : IPublicAreaFacade, IDisposable
{
private UnitOfWork _unitOfWork;
public PublicAreaFacade(IDataContext context)
{
_unitOfWork = new UnitOfWork(context);
}
}
The BLL:
public abstract class BaseManager
{
protected IDataContext Context;
public BaseManager(IDataContext context)
{
this.Context = context;
}
}
The Repository:
public class Repository<TEntity>
where TEntity : class
{
internal PublicAreaContext _context;
internal DbSet<TEntity> _dbSet;
public Repository(IDataContext context)
{
this._context = context as PublicAreaContext;
}
}
IDataContext is an interface that is implemented by my DbContext:
public partial class PublicAreaContext : DbContext, IDataContext
Now, how I mock EF and how I write the tests:
[TestInitialize]
public void Init()
{
this._mockContext = ContextHelper.CreateCompleteContext();
}
Where ContextHelper.CreateCompleteContext() is:
public static PublicAreaContext CreateCompleteContext()
{
//Here I mock my context
var mockContext = new Mock<PublicAreaContext>();
//Here I mock my entities
List<Customer> customers = new List<Customer>()
{
new Customer() { Code = "123455" }, //Customer with no invoice
new Customer() { Code = "123456" }
};
var mockSetCustomer = ContextHelper.SetList(customers);
mockContext.Setup(m => m.Set<Customer>()).Returns(mockSetCustomer);
...
return mockContext.Object;
}
And here how I write my test:
[TestMethod]
public void Success()
{
#region Arrange
PrepareEasyPayPaymentRequest request = new PrepareEasyPayPaymentRequest();
request.CodiceEasyPay = "128855248542874445877";
request.Servizio = "MyService";
#endregion
#region Act
PublicAreaFacade facade = new PublicAreaFacade(this._mockContext);
PrepareEasyPayPaymentResponse response = facade.PrepareEasyPayPayment(request);
#endregion
#region Assert
Assert.IsTrue(response.Result == it.MC.WebApi.Models.ResponseDTO.ResponseResult.Success);
#endregion
}
Here It seems It works everything correctly!!! And It looks like my architecture is correct. But what if I want to insert/update an Entity? Nothing work anymore! I explain why:
As you can see I pass a *Request object (it is the DTO) to the facade, then in my TOA I generate my entity from the propertiess of the DTO:
private PaymentAttemptTrace CreatePaymentAttemptTraceEntity(string customerCode, int idInvoice, DateTime paymentDate)
{
PaymentAttemptTrace trace = new PaymentAttemptTrace();
trace.customerCode = customerCode;
trace.InvoiceId = idInvoice;
trace.PaymentDate = paymentDate;
return trace;
}
PaymentAttemptTrace is the Entity I will inserto to Entity Framework.. It is not mocked and I cannot inject it. So even if I pass my mocked context (IDataContext), when I try to insert an Entity that is not mocked my test fails!
Here that doubt about I have a wrong architecture has raised!
So, what's wrong? The architecture or the way I use moq?
Thank you for help
UPDATE
Here how I test my code.. For example, I want to test the trace of a payment..
Here the test:
[TestMethod]
public void NoPaymentDate()
{
TracePaymentAttemptRequest request = new TracePaymentAttemptRequest();
request.AliasTerminale = "MyTerminal";
//...
//I create my request object
//You can see how I create _mockContext above
PublicAreaFacade facade = new PublicAreaFacade(this._mockContext);
TracePaymentAttemptResponse response = facade.TracePaymentAttempt(request);
//My asserts
}
Here the facade:
public TracePaymentAttemptResponse TracePaymentAttempt(TracePaymentAttemptRequest request)
{
TracePaymentAttemptResponse response = new TracePaymentAttemptResponse();
try
{
...
_unitOfWork.PaymentsManager.SavePaymentAttemptResult(
easyPay.CustomerCode,
request.CodiceTransazione,
request.EsitoPagamento + " - " + request.DescrizioneEsitoPagamento,
request.Email,
request.AliasTerminale,
request.NumeroContratto,
easyPay.IdInvoice,
request.TotalePagamento,
paymentDate);
_unitOfWork.Commit();
response.Result = ResponseResult.Success;
}
catch (Exception ex)
{
response.Result = ResponseResult.Fail;
response.ResultMessage = ex.Message;
}
return response;
}
Here how I developed the PaymentsManager:
public PaymentAttemptTrace SavePaymentAttemptResult(string customerCode, string transactionCode, ...)
{
//here the problem... PaymentAttemptTrace is the entity of entity framework.. Here i do the NEW of the object.. It should be injected, but I think it would be a wrong solution
PaymentAttemptTrace trace = new PaymentAttemptTrace();
trace.customerCode = customerCode;
trace.InvoiceId = idInvoice;
trace.PaymentDate = paymentDate;
trace.Result = result;
trace.Email = email;
trace.Terminal = terminal;
trace.EasypayCode = transactionCode;
trace.Amount = amount;
trace.creditCardId = idCreditCard;
trace.PaymentMethod = paymentMethod;
Repository<PaymentAttemptTrace> repository = new Repository<PaymentAttemptTrace>(base.Context);
repository.Insert(trace);
return trace;
}
In the end how I wrote the repository:
public class Repository<TEntity>
where TEntity : class
{
internal PublicAreaContext _context;
internal DbSet<TEntity> _dbSet;
public Repository(IDataContext context)
{
//the context is mocked.. Its type is {Castle.Proxies.PublicAreaContextProxy}
this._context = context as PublicAreaContext;
//the entity is not mocked. Its type is {PaymentAttemptTrace} but should be {Castle.Proxies.PaymentAttemptTraceProxy}... so _dbSet result NULL
this._dbSet = this._context.Set<TEntity>();
}
public virtual void Insert(TEntity entity)
{
//_dbSet is NULL so "Object reference not set to an instance of an object" exception is raised
this._dbSet.Add(entity);
}
}
Your architecture looks good, but the implementation is flawed. It is leaking abstraction.
In your diagram the Façade layer depends only on the BLL but when you look at the PublicAreaFacade's constructor you will see that in reality it has a direct dependency to an interface from the Repository layer:
public PublicAreaFacade(IDataContext context)
{
_unitOfWork = new UnitOfWork(context);
}
This should not be. It should only take its direct dependency as input -- the PaymentsManager or -- even better -- an interface of it:
public PublicAreaFacade(IPaymentsManager paymentsManager)
{
...
}
The concequence is that your code becomes way more testable. When you look at your tests now you see that you have to mock the most inner layer of your system (i.e. the IDataContext and even its entity accessors Set<TEntity>) altough you are testing one of the most outer layers of your system (the PublicAreaFacade class).
This is how a unit test for the TracePaymentAttempt method would look like if the PublicAreaFacade only depended on IPaymentsManager:
[TestMethod]
public void CallsPaymentManagerWithRequestDataWhenTracingPaymentAttempts()
{
// Arrange
var pm = new Mock<IPaymentsManager>();
var pa = new PulicAreaFacade(pm.Object);
var payment = new TracePaymentAttemptRequest
{
...
}
// Act
pa.TracePaymentAttempt(payment);
// Assert that we call the correct method of the PaymentsManager with the data from
// the request.
pm.Verify(pm => pm.SavePaymentAttemptResult(
It.IsAny<string>(),
payment.CodiceTransazione,
payment.EsitoPagamento + " - " + payment.DescrizioneEsitoPagamento,
payment.Email,
payment.AliasTerminale,
payment.NumeroContratto,
It.IsAny<int>(),
payment.TotalePagamento,
It.IsAny<DateTime>()))
}
Pass IUnitOfWork into the Facade or BLL layer constructor, whichever one makes calls on the unit of work directly. Then you can setup what the Mock<IUnitOfWork> is returning in your tests. You should not need to pass IDataContext to everything except maybe the repo constructors and the unit of work.
For example, if the Facade has a method PrepareEasyPayPayment that makes a repo call through a UnitOfWork call, setup the mock like this:
// Arrange
var unitOfWork = new Mock<IUnitOfWork>();
unitOfWork.Setup(x => x.PrepareEasyPayPaymentRepoCall(request)).Returns(true);
var paymentFacade = new PaymentFacade(unitOfWork.Object);
// Act
var result = paymentFacade.PrepareEasyPayPayment(request);
Then you've mocked out the data call and can more easily test your code in the Facade.
For the insert testing, you should have a Facade method like CreatePayment which takes a PrepareEasyPayPaymentRequest. Inside that CreatePayment method, it should reference the repo, probably through the unit of work, like
var result = _unitOfWork.CreatePaymentRepoCall(request);
if (result == true)
{
// yes!
}
else
{
// oh no!
}
What you want to mock for unit testing is that this create/insert repo call returns true or false so you can test the code branches after the repo call has completed.
You can also test that the insert call was made as expected, but that's usually not as valuable unless the parameters for that call have a lot of logic involved in building them.
it sounds like you need to change the code a little bit. Newing things introduces hardcoded dependencies and makes them untestable, so try to abstract them away. Maybe you can hide everything to do with EF behind another layer, then all you have to do is mock that particular layer layer and never touch EF.
You can use this open source framework for unit testing which is good to mock entity framework dbcontext
https://effort.codeplex.com/
Try this will help you to mock your data efficiently.

How to wrap HttpClient for testability in C#

I'm calling an external API and would like my API to be unit testable. And to do that, i'm trying to wrap HttpClient. I only need one method for now.
Here is my interface.
public interface IHttpClient
{
Task<string> GetStringAsync(string url);
}
And this is how I implemented it.
public class HttpClientWrapper : IHttpClient
{
private readonly HttpClient _httpClient;
public HttpClientWrapper()
{
// I could also inject this but I think this will be fine as is.
_httpClient = new HttpClient(new HttpClientHandler(), false);
}
public async Task<string> GetStringAsync(string url)
{
//validate url here
return await _httpClient.GetStringAsync(url);
}
}
Doubts I have? is this the right way to do it? Will setting the bool parameter result in resource leaking here? I read a couple of conflicting ideas about whether HttpClient has to be disposed on every call or not. I took, the not disposing side but am not really quite certain though.
If there is a way to use HttpClient without having a wrapper but make the API testable, that will be great too. But so far, i failed to get that working.
Thanks,
CleanKoder
While it could still be nice to create an interface for the client, the HttpClient class is actually designed with testability in mind! When instantiating your HttpClient you can inject a custom HttpMessageHandler. By overriding Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in this class, you can interrupt all requests before they are actually written to the socket, inspecting them and returning whatever you see fit.
Here is an example of such a test double I wrote in a project, feel free to modify it to suit your needs:
public class FakeHttpMessageHandler : HttpMessageHandler
{
public HttpRequestMessage LastRequest;
public string LastRequestString = string.Empty;
public string ResponseContent = string.Empty;
public HttpStatusCode ResponseStatusCode = HttpStatusCode.OK;
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (request.Content != null)
{
LastRequestString = await request.Content.ReadAsStringAsync();
}
LastRequest = request;
return await Task.FromResult(new HttpResponseMessage
{
StatusCode = ResponseStatusCode,
Content = new StringContent(ResponseContent)
});
}
}
You could also use some isolation framework like NSubstitute if you think that's more appropriate for your project.