NUnit & MOQ: Testing a try catch that calls another method when an Exception is caught - nunit

I understand that the MOQ framework wasn't really designed to help in this instance, but perhaps you might be able to help...
I have a method that uses a try/catch that calls a notification method whenever an exception is thrown. What I am trying to do is create an integration/unit test that checks to make sure SendNotification is called when any exception is thrown.
Method Under Test:
public virtual void MonitorIntradayBuilds(IIntradayBuilds intradayBuilds)
{
try
{
var intradayBuildFound = intradayBuilds.CheckForIntradayBuilds();
if (intradayBuildFound && !IntradayBuildsComplete && !DailyBuildsFound)
{
IntradayBuildsComplete = intradayBuilds.StartIntradayBuilds();
//should start daily builds?
}
}
catch (Exception ex)
{
SendNotification("MonitorIntradayBuilds threw an exception", ex);
}
}
Test Case:
[Test]
public void it_should_notify_developers_immediately_if_there_is_a_problem_when_checking_for_intraday_builds()
{
//Arrange
var mockDua = new Mock<DUA>();
var mockIB = new Mock<IIntradayBuilds>();
//Act
mockIB.Setup(x => x.CheckForIntradayBuilds()).Throws(new Exception());
mockDua.Object.MonitorIntradayBuilds(mockIB.Object);
//Assert
mockDua.Verify(x => x.SendNotification(It.IsAny<string>(), It.IsAny<Exception>()), Times.Once);
}
I keep hitting a Moq.MockException and then see that SendNotification "expected an invocation on the mock once, but was 0 times..."
I've tried using the [ExpectedException] attribute on the test case, but to no avail. It makes the test pass, but still doesn't call the SendNotification method.
Any ideas?

Solved it.
Turns out you need to set the CallBase property on the System Under Test that you are mocking up.
Test case is now:
[Test]
public void it_should_notify_developers_immediately_if_there_is_a_problem_when_checking_for_intraday_builds()
{
//Arrange
var mockDua = new Mock<DUA>();
var mockIB = new Mock<IIntradayBuilds>();
mockDua.CallBase = true; // <<<< Added this line!
//Act
mockIB.Setup(x => x.CheckForIntradayBuilds()).Throws(new Exception());
mockDua.Object.MonitorIntradayBuilds(mockIB.Object);
//Assert
mockDua.Verify(x => x.SendNotification(It.IsAny<string>(), It.IsAny<Exception>()), Times.Once);
}
Hopefully someone else finds it helpful :)

Related

AspNet Boilerplate Parallel DB Access through Entity Framework from an AppService

We are using ASP.NET Zero and are running into issues with parallel processing from an AppService. We know requests must be transactional, but unfortunately we need to break out to slow running APIs for numerous calls, so we have to do parallel processing.
As expected, we are running into a DbContext contingency issue on the second database call we make:
System.InvalidOperationException: A second operation started on this context
before a previous operation completed. This is usually caused by different
threads using the same instance of DbContext, however instance members are
not guaranteed to be thread safe. This could also be caused by a nested query
being evaluated on the client, if this is the case rewrite the query avoiding
nested invocations.
We read that a new UOW is required, so we tried using both the method attribute and the explicit UowManager, but neither of the two worked.
We also tried creating instances of the referenced AppServices using the IocResolver, but we are still not able to get a unique DbContext per thread (please see below).
public List<InvoiceDto> CreateInvoices(List<InvoiceTemplateLineItemDto> templateLineItems)
{
List<InvoiceDto> invoices = new InvoiceDto[templateLineItems.Count].ToList();
ConcurrentQueue<Exception> exceptions = new ConcurrentQueue<Exception>();
Parallel.ForEach(templateLineItems, async (templateLineItem) =>
{
try
{
XAppService xAppService = _iocResolver.Resolve<XAppService>();
InvoiceDto invoice = await xAppService
.CreateInvoiceInvoiceItem();
invoices.Insert(templateLineItems.IndexOf(templateLineItem), invoice);
}
catch (Exception e)
{
exceptions.Enqueue(e);
}
});
if (exceptions.Count > 0) throw new AggregateException(exceptions);
return invoices;
}
How can we ensure that a new DbContext is availble per thread?
I was able to replicate and resolve the problem with a generic version of ABP. I'm still experiencing the problem in my original solution, which is far more complex. I'll have to do some more digging to determine why it is failing there.
For others that come across this problem, which is exactly the same issue as reference here, you can simply disable the UnitOfWork through an attribute as illustrated in the code below.
public class InvoiceAppService : ApplicationService
{
private readonly InvoiceItemAppService _invoiceItemAppService;
public InvoiceAppService(InvoiceItemAppService invoiceItemAppService)
{
_invoiceItemAppService = invoiceItemAppService;
}
// Just add this attribute
[UnitOfWork(IsDisabled = true)]
public InvoiceDto GetInvoice(List<int> invoiceItemIds)
{
_invoiceItemAppService.Initialize();
ConcurrentQueue<InvoiceItemDto> invoiceItems =
new ConcurrentQueue<InvoiceItemDto>();
ConcurrentQueue<Exception> exceptions = new ConcurrentQueue<Exception>();
Parallel.ForEach(invoiceItemIds, (invoiceItemId) =>
{
try
{
InvoiceItemDto invoiceItemDto =
_invoiceItemAppService.CreateAsync(invoiceItemId).Result;
invoiceItems.Enqueue(invoiceItemDto);
}
catch (Exception e)
{
exceptions.Enqueue(e);
}
});
if (exceptions.Count > 0) {
AggregateException ex = new AggregateException(exceptions);
Logger.Error("Unable to get invoice", ex);
throw ex;
}
return new InvoiceDto {
Date = DateTime.Now,
InvoiceItems = invoiceItems.ToArray()
};
}
}
public class InvoiceItemAppService : ApplicationService
{
private readonly IRepository<InvoiceItem> _invoiceItemRepository;
private readonly IRepository<Token> _tokenRepository;
private readonly IRepository<Credential> _credentialRepository;
private Token _token;
private Credential _credential;
public InvoiceItemAppService(IRepository<InvoiceItem> invoiceItemRepository,
IRepository<Token> tokenRepository,
IRepository<Credential> credentialRepository)
{
_invoiceItemRepository = invoiceItemRepository;
_tokenRepository = tokenRepository;
_credentialRepository = credentialRepository;
}
public void Initialize()
{
_token = _tokenRepository.FirstOrDefault(x => x.Id == 1);
_credential = _credentialRepository.FirstOrDefault(x => x.Id == 1);
}
// Create an invoice item using info from an external API and some db records
public async Task<InvoiceItemDto> CreateAsync(int id)
{
// Get db record
InvoiceItem invoiceItem = await _invoiceItemRepository.GetAsync(id);
// Get price
decimal price = await GetPriceAsync(invoiceItem.Description);
return new InvoiceItemDto {
Id = id,
Description = invoiceItem.Description,
Amount = price
};
}
private async Task<decimal> GetPriceAsync(string description)
{
// Simulate a slow API call to get price using description
// We use the token and credentials here in the real deal
await Task.Delay(5000);
return 100.00M;
}
}

Unity Editor detect when build fails

I'm trying to use IPreProcessBuildWithReport and IPostProcessBuildWithReport to add a game object to the scene right before build, and promptly delete it from the scene when the build finishes. The goal is to reduce all that I can from the hierarchy during the development but include these objects during the build.
My issue occurs when the build fails (due to some error), it adds the game object before the build started but never reached the code to delete the game object when it fails.
Is there a similar method to detect when the build fails without building my own build player pipeline? I really don't want to stray away from unity's default build pipeline if I don't need to.
If there was no easy way, I was trying to think if maybe there was a way to track the buildfailed exception or error and run a method if it occurs.
Thanks, let me know what you guys think.
EDIT: As requested, here is an example:
class CustomBuildPipeline : MonoBehaviour, IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
public int callbackOrder => 0;
// CALLED BEFORE THE BUILD
public void OnPreprocessBuild(BuildReport report)
{
// Create and add gameobjects to scene
}
// CALLED AFTER THE BUILD
public void OnPostprocessBuild(BuildReport report)
{
// Remove gameobjects from scene once built
}
}
}
PreProcess Interface
PostProcess Interface
I was wondering if there was a possible solution by somehow detecting when this buildexception was thrown and running code following.
EDIT 2: I found this post that has possible solutions, however, it may not be as elegant as I'd prefer. I'll try some things out and report back.
I used the post in the 'EDIT 2' to come up with a decent solution. I don't know if it will work 100% of the time and I would love for someone to correct me if I have chosen a poor solution. This should allow me to run code before the build starts, and if the build fails or succeeds without changing the unity build pipeline.
class CustomBuildPipeline : MonoBehaviour, IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
public int callbackOrder => 0;
// CALLED BEFORE THE BUILD
public void OnPreprocessBuild(BuildReport report)
{
// Start listening for errors when build starts
Application.logMessageReceived += OnBuildError;
}
// CALLED DURING BUILD TO CHECK FOR ERRORS
private void OnBuildError(string condition, string stacktrace, LogType type)
{
if (type == LogType.Error)
{
// FAILED TO BUILD, STOP LISTENING FOR ERRORS
Application.logMessageReceived -= OnBuildError;
}
}
// CALLED AFTER THE BUILD
public void OnPostprocessBuild(BuildReport report)
{
// IF BUILD FINISHED AND SUCCEEDED, STOP LOOKING FOR ERRORS
Application.logMessageReceived -= OnBuildError;
}
}
}
This approach is using a custom build handler, but still uses the default build pipeline.
Use BuildHandler.OnBuildStarted instead of (or in addition to) IPreprocessBuildWithReport for pre-processing. For post-processing use BuildHandler.OnBuildCleanup, which is called when a build completes or fails. Can also be used in conjunction with IPostprocessBuildWithReport.
[InitializeOnLoad]
public class BuildHandler : MonoBehaviour
{
public static event Action OnBuildStarted;
public static event Action OnBuildCleanup;
static BuildHandler()
{
BuildPlayerWindow.RegisterBuildPlayerHandler(Build);
}
private static void Build(BuildPlayerOptions buildOptions)
{
try
{
BuildStarted();
//now start Unity's default building procedure
BuildPlayerWindow.DefaultBuildMethods.BuildPlayer(buildOptions);
}
catch (BuildPlayerWindow.BuildMethodException) { } //logged internally
catch (Exception ex)
{
Exception log = ex.InnerException == null ? ex : ex.InnerException;
Debug.LogException(log);
Debug.LogErrorFormat("{0} in BuildHandler: '{1}'", log.GetType().Name, ex.Message);
}
finally
{
BuildCleanup();
}
}
private static void BuildStarted()
{
try
{
if (OnBuildStarted != null)
OnBuildStarted.Invoke();
}
catch (Exception ex)
{
throw new Exception("OnBuildStarted failed", ex);
}
}
private static void BuildCleanup()
{
if (OnBuildCleanup != null)
{
foreach (Action cleanupBuild in OnBuildCleanup.GetInvocationList())
{
try
{
cleanupBuild.Invoke();
}
catch (Exception ex)
{
Object context = cleanupBuild.Target as Object;
Debug.LogException(ex, context);
Debug.LogWarning("Caught exception while BuildHandler.OnBuildCleanup... Continuing");
}
}
}
}
}

How to mock a MongoDB collection of type IMongoCollection<T> to return some predefined data?

Below is my code:
Controller/Action:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(CustomerViewModel model, string returnUrl = null)
{
try
{
ViewData["ReturnUrl"] = returnUrl;
// when debugging the test, _dbContext.Customers throws exception
CustomerDoc existingCustomer = await _dbContext.Customers.Find(o => o.email == model.email).FirstOrDefaultAsync();
if (existingCustomer != null)
{
ModelState.AddModelError("Email", "email already used.");
}
// other checkings
if (!ModelState.IsValid)
{
return View(model);
}
// if model state is valid, do something here
}
catch (Exception ex)
{
return View(model);
}
return View(model);
}
And my unit test code is:
[Fact]
public async Task should_return_view_with_errors_when_email_already_exists()
{
IEnumerable<CustomerDoc> customers = new List<CustomerDoc>
{
new CustomerDoc
{
email = "test#test.com"
}
};
_dbContextMock.SetupAllProperties();
// below line is causing the error
_dbContextMock.Setup(c => c.Customers).Returns(() =>(IMongoCollection<CustomerDoc>)customers);
CustomerViewModel model = new CustomerViewModel
{
email = "test#test.com"
};
CreateController();
var result = await _controller.Register(model);
Assert.IsType<ViewResult>(result);
Assert.False(_controller.ModelState.IsValid);
Assert.True(_controller.ModelState.ContainsKey("Email"));
}
As you can see in my unit test code comment, I am trying to mock a IMongoCollection to return some data. But I am not able to do so because _dbContext.Customers is throwing exception.
How can I mock IMongoCollection to return some predefined data?
I am using
asp.net core 2.1.0
mongodb driver 2.7.0
You declare customers as a List:
IEnumerable<CustomerDoc> customers = new List<CustomerDoc>
but then try to cast it to IMongoCollection
() =>(IMongoCollection<CustomerDoc>)customers
There's two immediate directions (but both have further issues to deal with):
1) Just return the list without the cast
() => customers
but I can't see the type of c.Customers so I suspect this will just move the issue. I'll take a guess that it's IMongoCollection<CustomerDoc> which is why you're trying to do the cast in the first place? This is problematic as the .Returns would need to be be associated with a function performing the equivalent of c.Customer.Find(). Even so, it's probably better than the alternative.
2) Changing the customers variable to a type that implements IMongoCollection.
Option 1 feels like the way to go as option 2 forces you to start dealing with lots of logic that really shouldn't be relevant to this piece of code.

Why Shiro's SubjectCallable need invoke restore method?

SubjectCallable's call method:
public V call() throws Exception {
try {
threadState.bind();
return doCall(this.callable);
} finally {
threadState.restore();
}
}
1.bind method is necsssary, but restore is why?
public void bind() {
SecurityManager securityManager = this.securityManager;
if ( securityManager == null ) {
//try just in case the constructor didn't find one at the time:
securityManager = ThreadContext.getSecurityManager();
}
this.originalResources = ThreadContext.getResources();
ThreadContext.remove();
ThreadContext.bind(this.subject);
if (securityManager != null) {
ThreadContext.bind(securityManager);
}
}
public void restore() {
ThreadContext.remove();
if (!CollectionUtils.isEmpty(this.originalResources)) {
ThreadContext.setResources(this.originalResources);
}
}
2.originalResources is use to do ? each time enter the AbstractShiroFilter will create a new subject and invoke it's execute method, the originalResources seems useless.
General thread health. You need to clean up resource in case the thread is re-used (very common). And it would help with garbage collection too.
Do you ever go hiking? Leave no trace ;)

Test a method that does something as well as throws an exception

I'm getting started with TDD (and MoQ). I have a method that takes in an Order and creates a unique CustomerId for that Order.
public class CustomerService
{
public CustomerService(IOrderRepository orderRepo)
{
_orderRepo = orderRepo;
}
public string Create(Order order)
{
//1. Save the Order that comes in, irrespective of being valid or not.
_orderRepo.Save(order);
//2. If the order is invalid, throw an exception.
if (!isValid(order))
throw new ArgumentException();
//3. Create a Customer, generate a unique CustomerId and return that.
return createCustomerAndGenerateCustomerId(order);
}
}
The following test doesn't seem to be working correctly:
[Test]
[ExpectedException(typeof(ArgumentException))]
public void Create_WhenPassedInvalidOrder_StillPersistsIt()
{
//Arrange
var order = new Order(); //This is invalid, as it has some mandatory fields missing
var mockOrderRepo = new Mock<IOrderRepository>();
var customerService = new CustomerService(mockOrderRepo.Object);
//Act
customerService.Create(order); //This should call Save() on the order repo, but still throw an exception.
//Assert
mockOrderRepo.Verify(o => o.Save(order), Times.Once());
}
This test is always passing, even if I don't call _orderRepo.Save(). What am I doing wrong?
You cannot use ExpectedException in this scenario because Nunit will try/catch the exception on the test level so your mockOrderRepo.Verify never gets called.
So you manually need to try catch your customerService.Create call - and if you want manually assert on the thrown exception - or you the Assert.Throws if you're using Nunit 2.5 or higher:
[Test]
public void Create_WhenPassedInvalidOrder_StillPersistsIt()
{
//Arrange
var order = new Order();
var mockOrderRepo = new Mock<IOrderRepository>();
var customerService = new CustomerService(mockOrderRepo.Object);
//Act
Assert.Throws<ArgumentException>(() => customerService.Create(order));
//Assert
mockOrderRepo.Verify(o => o.Save(order), Times.Once());
}