Base solution for your next web application
Open Closed

Very slow application scaffolding for unit tests #7725


User avatar
0
lojelis created

Hi!

I have troubles using the test project of the ASP.NET Zero template. The tests are working correctly however, they take a lot of time to run. I think that the issue comes from the class AbpIntegratedTestBase. I explain myself with two examples:

  • I have a test class that does not inherit from AbpIntegratedTestBase. The class only reads some to text files, extract data and check if everything is correct. The test takes 33ms to run.
  • I have another test class that makes a call to the application's API. The test class inherits from AbpIntegratedTestBase to scaffold the app before testing. In the test I only make a single call to an endpoint that returns a basic list of items. It tooks 2 minutes to run...

I let you imagine the time it takes to run all the tests suit (more than an hour). It makes the test project totaly worthlessness. I would like to know if you have a solution to solve this issue because the test project is one of the best part of your template. Thanks in advance.

Best regards, Nicolas Prugne


11 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @lojelis

    This is totally an unacceptable duration. AbpIntegratedTestBase's custructor is executed before every test and it inserts test data for test cases but in our case, it takes 1 or 2 minutes for all default tests.

    Have you modified anything related to tests ? If not, could you share your test project with us via email (to [email protected]) ?

    Thanks

  • User Avatar
    0
    lojelis created

    Hi thanks for your reply!

    I am requisting the autorisation from my hierachy to share the project with you. While I am waiting for the answer, I can share some small pieces of code to give you some clues.

     public abstract class AppTestBase : AbpIntegratedTestBase<COPYloteTestModule>
     {
        protected AppTestBase() : base(true, null)
        {
            //SeedTestData();
            //LoginAsDefaultTenantAdmin();
        }
     }
    

    I have voluntary commented the two lines to see if the performance issue does not come from here but without success. The test still take 2 minutes to run. Here is the prototype of our test class:

        public class EmployeService_Tests : AppTestBase
        {
            [Fact]
            public async void Should_Get_All_The_Employees()
            {
                var employes = await _employeService.GetAllAsync();
                Assert.Equal(5, employes.Items.Count);
            }
        }
    

    Regards, Nicolas

  • User Avatar
    0
    lojelis created

    Another relevant piece of code. The following takes 2 minutes to run:

    public abstract class AppTestBase : AbpIntegratedTestBase<COPYloteTestModule>
    {
         protected AppTestBase() : base(true, null)
         {
         }
     }
     
    public class Hello_Test : AppTestBase
    {
       [Fact]
        public void Should_Write_Hello_World()
        {
            Console.WriteLine("Hello World");
        }
    }
    

    While this takes 182ms:

    public abstract class AppTestBase : AbpIntegratedTestBase<COPYloteTestModule>
    {
         protected AppTestBase() : base(false, null)
         {
         }
     }
     
    public class Hello_Test : AppTestBase
    {
       [Fact]
        public void Should_Write_Hello_World()
        {
            Console.WriteLine("Hello World");
        }
    }
    

    The only difference is the parameter initializeAbp of the base class AbpIntegratedTestBase which is turned to false.

    So what can slow down ABP initialization? Is it the total number of app services in the project? Currently we have 70 services. With :

    • 173 GET methods
    • 158 POST methods
    • 43 PUT methods
    • 26 DELETE methods

    Which makes 400 endpoints. Maybe the initialization is slow because of this? Have you ever try to use ABP for a project of this size (or even bigger)?

    Best regards, Nicolas

  • User Avatar
    0
    maliming created
    Support Team

    We are waiting for your project code.

  • User Avatar
    0
    lojelis created

    I can't share the project because I have confidentiality engagements with my client. However I have discovered that some other ABP users had the issue in the past: https://support.aspnetzero.com/QA/Questions/444.

    That's exactly my case. I have studied more in details the problem and it comes from the class AbpBootstrapper and its method Initialize.

    Did you find a solution in the past?

    Best regards, Nicolas

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @lojelis

    There was different problems in the past but it was related to ABP Framework and fixed. Is it possibl to share your COPYloteTestModule class ?

    Thanks,

  • User Avatar
    0
    lojelis created

    Yes I can, here it is:

    using System;
    using System.IO;
    using Abp;
    using Abp.AspNetZeroCore;
    using Abp.AutoMapper;
    using Abp.Configuration.Startup;
    using Abp.Dependency;
    using Abp.Modules;
    using Abp.Net.Mail;
    using Abp.TestBase;
    using Abp.Zero.Configuration;
    using Castle.MicroKernel.Registration;
    using Microsoft.Extensions.Configuration;
    using Lojelis.COPYlote.Authorization.Users;
    using Lojelis.COPYlote.Configuration;
    using Lojelis.COPYlote.EntityFrameworkCore;
    using Lojelis.COPYlote.MultiTenancy;
    using Lojelis.COPYlote.Security.Recaptcha;
    using Lojelis.COPYlote.Tests.Configuration;
    using Lojelis.COPYlote.Tests.DependencyInjection;
    using Lojelis.COPYlote.Tests.UiCustomization;
    using Lojelis.COPYlote.Tests.Url;
    using Lojelis.COPYlote.Tests.Web;
    using Lojelis.COPYlote.UiCustomization;
    using Lojelis.COPYlote.Url;
    using NSubstitute;
    using Lojelis.COPYlote.App;
    using Lojelis.COPYlote.Tests.App.UserHelper;
    
    namespace Lojelis.COPYlote.Tests
    {
        [DependsOn(
            typeof(COPYloteApplicationModule),
            typeof(COPYloteEntityFrameworkCoreModule),
            typeof(AbpTestBaseModule))]
        public class COPYloteTestModule : AbpModule
        {
            public COPYloteTestModule(COPYloteEntityFrameworkCoreModule abpZeroTemplateEntityFrameworkCoreModule)
            {
                abpZeroTemplateEntityFrameworkCoreModule.SkipDbContextRegistration = true;
            }
    
            public override void PreInitialize()
            {
                var configuration = GetConfiguration();
    
                Configuration.UnitOfWork.Timeout = TimeSpan.FromMinutes(30);
                Configuration.UnitOfWork.IsTransactional = false;
                //Configuration.UnitOfWork.OverrideFilter("MayHaveSite",false);
    
                //Disable static mapper usage since it breaks unit tests (see https://github.com/aspnetboilerplate/aspnetboilerplate/issues/2052)
                Configuration.Modules.AbpAutoMapper().UseStaticMapper = false;
    
                //Use database for language management
                Configuration.Modules.Zero().LanguageManagement.EnableDbLocalization();
    
                RegisterFakeService<AbpZeroDbMigrator>();
    
                IocManager.Register<IAppUrlService, FakeAppUrlService>();
                IocManager.Register<IWebUrlService, FakeWebUrlService>();
                IocManager.Register<IRecaptchaValidator, FakeRecaptchaValidator>();
                IocManager.Register<IUserHelper, FakeUserHelper>();
    
                Configuration.ReplaceService<IAppConfigurationAccessor, TestAppConfigurationAccessor>();
                Configuration.ReplaceService<IEmailSender, NullEmailSender>(DependencyLifeStyle.Transient);
    
                Configuration.ReplaceService<IUiThemeCustomizerFactory, NullUiThemeCustomizerFactory>();
    
                Configuration.Modules.AspNetZero().LicenseCode = configuration["AbpZeroLicenseCode"];
    
                //Uncomment below line to write change logs for the entities below:
                Configuration.EntityHistory.IsEnabled = true;
                Configuration.EntityHistory.Selectors.Add("COPYloteEntities", typeof(User), typeof(Tenant));
            }
    
            public override void Initialize()
            {
                ServiceCollectionRegistrar.Register(IocManager);
            }
    
            private void RegisterFakeService<TService>()
                where TService : class
            {
                IocManager.IocContainer.Register(
                    Component.For<TService>()
                        .UsingFactoryMethod(() => Substitute.For<TService>())
                        .LifestyleSingleton()
                );
            }
    
            private static IConfigurationRoot GetConfiguration()
            {
                return AppConfigurations.Get(Directory.GetCurrentDirectory(), addUserSecrets: true);
            }
        }
    }
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @lojelis

    This seems fine actually. Did you used any tool to measure the method execution times ? It might help you to identify the slowest method/operation at least.

    By the way, could you also share specifications of your PC which you run unit tests (CPU, RAM etc...) ?

  • User Avatar
    0
    lojelis created

    Hi @ismcagdas,

    Here is the specifications of my computer (sorry it's in french but I think you can understand the main parts):

    I have used the Stopwatch Class from System.Diagnostics to measure the execution time of the Intialize method from the AbpBootstrapper class, but I haven't been in depth into the Initialize method. How can I measure the execution times of the method calls inside the method Initialize?

    Thanks in advance,

    Nicolas

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @lojelis

    It is in Framework's source code. We can try to help you via remote connection if you want. It would be faster that way. If so, could you send an email to [email protected] to arrange a meeting ?

    Thanks,

  • User Avatar
    0
    ismcagdas created
    Support Team

    This issue is closed because of no recent activity. Please open a new issue if you are still having this problem.