简体   繁体   中英

Unit testing for IDomainService with ASP.NET Boilerplate

I am unit testing ABP, but I got error below:

Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances. Object name: 'XXXDbContext'.

Here are my detailed steps:

  1. AppService

     public async Task<ProductDto> CreateProduct(CreateProductInput input) { var existing = // await _productManager.ProductRepository.FirstOrDefaultAsync(p => p.Name == input.Name); await _productManager.Products.Where(p => p.Name == input.Name).FirstOrDefaultAsync(); if (existing != null) throw new UserFriendlyException(L("ExistedRepeatedAd")); var newAdEntity = ObjectMapper.Map<Product>(input); // Rest of the code } 
  2. ProductManager

     public class ProductManager : IDomainService { private readonly IRepository<Product, long> _ProductRepository; private readonly IUnitOfWorkManager _unitOfWorkManager; public ProductsManager( IRepository<Product, long> ProductRepository, IUnitOfWorkManager unitOfWorkManager) { _ProductRepository = ProductRepository; _unitOfWorkManager = unitOfWorkManager; } #region Products public IRepository<Product, long> ProductRepository { get { return _ProductRepository; } } public IQueryable<Product> Products { get { return _ProductRepository.GetAll(); } } public async Task<Product> CreateProduct(Product input) { var result = await _ProductRepository.InsertAsync(input); await _unitOfWorkManager.Current.SaveChangesAsync(); return result; } #endregion } 

It will throw error this line:

await _adManager.Ads.Where(p => p.Name == input.Name).FirstOrDefaultAsync();

But if I use this instead, it will work:

await _adManager.AdRepository.FirstOrDefaultAsync(p => p.Name == input.Name);

In addition, I get _unitOfWorkManager.Current as null in the above code.
Is there any suggestion?

UnitOfWork Attribute

Add [UnitOfWork] attribute and make it a virtual method:

[UnitOfWork]
public virtual async Task<ProductDto> CreateProduct(CreateProductInput input)
{
    var existing = await _productManager.Products
        .Where(p => p.Name == input.Name)
        .FirstOrDefaultAsync();

    // ...
}
[UnitOfWork]
public virtual async Task<Product> CreateProduct(Product input)
{
    var result = await _ProductRepository.InsertAsync(input);
    await _unitOfWorkManager.Current.SaveChangesAsync();
    return result;
}

See: UnitOfWork Attribute Restrictions

You can use UnitOfWork attribute for:

  • All public or public virtual methods for classes that are used over an interface (Like an application service used over a service interface).
  • All public virtual methods for self-injected classes (Like MVC Controllers and Web API Controllers ).
  • All protected virtual methods.

IUnitOfWorkManager

You can inject IUnitOfWorkManager to begin a UnitOfWork explicitly:

public async Task<Product> CreateProduct(Product input)
{
    using (var uow = _unitOfWorkManager.Begin())
    {
        var result = await _ProductRepository.InsertAsync(input);
        await _unitOfWorkManager.Current.SaveChangesAsync();

        await uow.CompleteAsync();

        return result;
    }
}

My issue is resolved by creating Interface for my appservice and then Resolve this Interface in my test projects.

Thanks for the suggestion from aaron, but it would be complex to using uniofwork in my every application service.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM