Activities of "enisn"

Hi @Yaduraj

Can you provide a simple scenario to reproduce problem? I think problem occurs according to your dependencies, For example, you've mocked a Repository but it doesn't return foreign key id or mocked id doesn't match with related entity's id.

Otherwise, in integration test, you shouldn't mock repositories, you should use already seeded datas for testing. Let me introduce a full example that would explain what I meant:

Think there is a PurchaseAppService but this service uses IPaymentService to call a 3rd party API and make payment. Following example shows how to mock 3rd Party PaymentService

  • A couple of DTOs:
public class PaymentResult
{
    public string Code { get; set; }
    public bool Succeeded { get; set; }
}

public class PaymentInput
{
    public decimal Price { get; set; }
    public string SomePaymentInfo { get; set; }
}

public class PurchaseInput
{
    public Guid ProductId { get; set; }
    public int Amount { get; set; }
}
  • And interfaces:
public interface IPaymentService : ITransientDependency
{
    Task<PaymentResult> MakePaymentAsync(PaymentInput input);
}

public interface IPurchaseAppService : IApplicationService
{
    Task PurchaseAsync(PurchaseInput input);
}
  • See the implementation of PurchaseAppService, that calls a 3rd party service over its interface.
public class PurchaseAppService : ApplicationService, IPurchaseAppService
{
    protected IPaymentService PaymentService { get; }
    protected IRepository<Product> ProductRepository { get; }

    public PurchaseAppService(
        IPaymentService paymentService,
        IRepository<Product> productRepository)
    {
        PaymentService = paymentService;
        ProductRepository = productRepository;
    }

    public async Task PurchaseAsync(PurchaseInput input)
    {
        var product = await ProductRepository.GetAsync(x => x.Id == input.ProductId);

        // 3rd Party Service Call
        var paymentResult = await PaymentService.MakePaymentAsync(new PaymentInput
        {
            Price = product.Price * input.Amount,
            SomePaymentInfo = "Some additrional data here..."
        });

        if (!paymentResult.Succeeded)
        {
            throw new BusinessException(message: "Payment is failed...");
        }

        // ...
        // There might be an insert code into Purchases table...
    }
}

  • Tests: In that case, I've already seeded a product with id Guid.Empty
public class PurchaseAppServiceTests : ProjectFApplicationTestBase
{
    private readonly IPurchaseAppService purchaseAppService;
    private IPaymentService paymentService;

    public PurchaseAppServiceTests()
    {
        purchaseAppService = GetRequiredService<IPurchaseAppService>();
    }

    protected override void AfterAddApplication(IServiceCollection services)
    {
        paymentService = Substitute.For<IPaymentService>();

        services.AddSingleton(paymentService);
    }

    [Fact]
    public async Task MakePayment_Should_Be_Failed()
    {
        var paymentInput = new PaymentInput { Price = 10, SomePaymentInfo = "..." };

        paymentService
            .MakePaymentAsync(paymentInput)
            .Returns(Task.FromResult(new PaymentResult { Code = "9901", Succeeded = false }));

        await Should.ThrowAsync<BusinessException>(async () =>
            await purchaseAppService.PurchaseAsync(new PurchaseInput
            {
                ProductId = Guid.Empty,
                Amount = 2
            })
        );
    }

    [Fact]
    public async Task MakePayment_Should_Be_Succeeded()
    {
        var paymentInput = new PaymentInput { Price = 10, SomePaymentInfo = "..." };

        paymentService
            .MakePaymentAsync(paymentInput)
            .Returns(Task.FromResult(new PaymentResult { Code = "0000", Succeeded = true }));

        await Should.NotThrowAsync(async () =>
            await purchaseAppService.PurchaseAsync(new PurchaseInput
            {
                ProductId = Guid.Empty,
                Amount = 2
            })
        );
    }
}

That test scenario mocks IPaymentService methods with no problem.

I highly suggest to check your all injected services and to make sure your seeder seeds consistent data.

And if you still think something is wrong, Feel free to share your scenario with code blocks

Can you share your project of part of project with us and we can see problem.

You can send it to info@abp.io with issue number (#1208) then we'll reproduce problem & see what's wrong.

Hi @Yaduraj,

Can you share some information about the problem that you faced?

Otherwise I have to redirect to NSubstitute Documentation

Hi,

Can you check *****ApplicationTestModule class in your test project for if there is a missing configuration or dependency.

Hi Yaduraj,

ABP Framework provides NSubstitute for mocking in testing.

See an example below:

public class BookStoreTest : BookStoreApplicationTestBase
{
    private ICurrentUser currentUser;

    protected override void AfterAddApplication(IServiceCollection services)
    {
        // Create a Substitute and replace original one in Service Collection
        currentUser = Substitute.For<ICurrentUser>();
        services.AddSingleton(currentUser);
    }

    [Fact]
    public async Task ShouldCurrentUserBeOwnerOfBook()
    {
        var userId = Guid.NewGuid();
        var username = "john.doe";
        
        // You can configure return values of Properties or Methods
        currentUser.Id.Returns(userId);
        currentUser.UserName.Returns(username);

        // Just a check if the id same. Also all services in the same IoC container will use that configuration.
        var id = currentUser.Id;
        id.ShouldBe(userId);
    }
}

I've just showed how to mock ICurrentUser, but you can mock any of your custom services that makes http call to a 3rd party API.

@learnabp let me introduce for your situation:

  • As a best-practice, BusinessException should be thrown from Domain layer. So You have to create your Exception in your Domain layer:
public class UserFriendlyException : BusinessException
{
    public UserFriendlyException(SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context)
    {
    }

    public UserFriendlyException(string tenantName)
    {
        // As an example, place your awesome unique code here
        Code = "Acme.BookStore:0001"; 

        WithData(nameof(TenantName), tenantName);
    }
    public string TenantName { get; set; }
}
  • You can throw like that:
    if (tenant != null)
    {
        throw new UserFriendlyException(Tenant.Name);
    }
  • You can localize what user sees in your localization files: en.json
    {
      "culture": "en",
      "texts": {
        "Acme.BookStore:0001": "Tenant Name {TenantName} already exists please choose another",
        //...
      }
    }
    
    You can display different messages for each language with that.

If you create a Business Exception like that, you won't see "internal error occured".

Let me know if that helps or not. @learnabp

If exception is inherited from Business exception and it has errorcode, exception detail text will be displayed from resources, exception message won't be displayed in UI automatically. You have to add a resource for errorcode of your exception

Hi @learnabp, I can't see UserFriendlyException but I'll suggest something below. If you already construct your exception same, please share your exception class too.


Make sure your exception is a DomainException and it has an error code and your localization json files have a resource with that error code as key.

You can examine 'AuthorAlreadyExistsException' in this sample

Hi @Leonardo.Willrich

As I understand, You don't want to change entire menu for tenant or host, just show/hide some menu items for host/tenant.

At this line I can show you a workaround:

  //if (_currentTenant.IsAvailable) // How to do it? Or what is the best way to do that?**
 if(_currentTenant.Id != null)
 {
   // tenant side
 }
 else
 {
  // host side
 }

Host doesn't have Id and it'll be null for host. Honestly, It's not best way or recommended to check host tenant but might help for you.

Showing 461 to 469 of 469 entries
Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11