c# नेट कोर: AppService, रिपोजिटरी, आदि के लिए Xunit टेस्ट में सभी निर्भरता इंजेक्शन निष्पादित करें




.net asp.net-core (3)

मैं AppService के लिए Xunit परीक्षण में निर्भरता इंजेक्शन को लागू करने की कोशिश कर रहा हूं। आदर्श लक्ष्य मूल एप्लिकेशन प्रोग्राम स्टार्टअप / कॉन्फ़िगरेशन चलाना है, और किसी भी निर्भरता इंजेक्शन का उपयोग करना है जो स्टार्टअप में था, मेरे परीक्षण में सभी DI को फिर से मजबूत करने के बजाय, प्रश्न में संपूर्ण लक्ष्य को पूरा करता है।

अपडेट: मोहसिन का जवाब करीब है। काम करने के लिए युगल वाक्यविन्यास / आवश्यकता त्रुटियों को अद्यतन करने की आवश्यकता है।

किसी कारण से, मूल एप्लिकेशन काम करता है और विभाग ऐप सेवा को कॉल कर सकता है। हालाँकि, यह Xunit में कॉल नहीं कर सकता है। अंत में मूल एप्लिकेशन से स्टार्टअप और कॉन्फ़िगरेशन का उपयोग करके टेस्टसर्वर काम कर रहा है। अब नीचे त्रुटि प्राप्त हो रही है:

Message: The following constructor parameters did not have matching fixture data: IDepartmentAppService departmentAppService

namespace Testing.IntegrationTests
{
    public class DepartmentAppServiceTest
    {
        public DBContext context;
        public IDepartmentAppService departmentAppService;

        public DepartmentAppServiceTest(IDepartmentAppService departmentAppService)
        {
            this.departmentAppService = departmentAppService;
        }

        [Fact]
        public async Task Get_DepartmentById_Are_Equal()
        {
            var options = new DbContextOptionsBuilder<SharedServicesContext>()
                .UseInMemoryDatabase(databaseName: "TestDatabase")
                .Options;
            context = new DBContext(options);

            TestServer _server = new TestServer(new WebHostBuilder()
                .UseContentRoot("C:\\OriginalApplication")
                .UseEnvironment("Development")
                .UseConfiguration(new ConfigurationBuilder()
                    .SetBasePath("C:\\OriginalApplication")
                    .AddJsonFile("appsettings.json")
                    .Build()).UseStartup<Startup>());

            context.Department.Add(new Department { DepartmentId = 2, DepartmentCode = "123", DepartmentName = "ABC" });
            context.SaveChanges();

            var departmentDto = await departmentAppService.GetDepartmentById(2);

            Assert.Equal("123", departmentDto.DepartmentCode);
        }
    }
}

मुझे यह त्रुटि प्राप्त हो रही है:

Message: The following constructor parameters did not have matching fixture data: IDepartmentAppService departmentAppService

वास्तविक आवेदन की तरह परीक्षण में निर्भरता इंजेक्शन का उपयोग करने की आवश्यकता है। मूल आवेदन यह करता है। नीचे दिए गए उत्तर वर्तमान में पर्याप्त नहीं हैं, एक मॉकिंग का उपयोग करता है जो वर्तमान लक्ष्य नहीं है, अन्य उत्तर नियंत्रक का उपयोग करता है जो प्रश्न उद्देश्य को बायपास करता है।

नोट: IDepboxAppService में IDepboxRepository पर निर्भरता है जो स्टार्टअप क्लास और ऑटोमैपर निर्भरता में भी इंजेक्ट की जाती है। यही कारण है कि पूरे स्टार्टअप क्लास को कॉल करना।

अच्छे संसाधन:

कैसे यूनिट परीक्षण asp.net कोर आवेदन निर्माता निर्भरता इंजेक्शन के साथ

Xunit परियोजना में निर्भरता इंजेक्शन


जब आप परीक्षण कर रहे हैं। आपको मॉकिंग लाइब्रेरी का उपयोग करने की आवश्यकता है या अपनी सेवा को सीधे कन्ट्रैक्टर पर इंजेक्ट करें।

public DBContext context;
public IDepartmentAppService departmentAppService;

/// Inject DepartmentAppService here
public DepartmentAppServiceTest(DepartmentAppService departmentAppService)
{
    this.departmentAppService = departmentAppService;
}

आप एकीकरण परीक्षण के साथ इकाई परीक्षण मिश्रण कर रहे हैं। TestServer एकीकरण परीक्षण के लिए है और यदि आप फिर से रजिस्टर निर्भरता से बचने के लिए Startup क्लास का पुन: उपयोग करना चाहते हैं, तो आपको HttpClient उपयोग करना चाहिए और IDepartmentAppService उपयोग करने वाले नियंत्रक और कार्रवाई के लिए HTTP कॉल करना चाहिए।

यदि आप इकाई परीक्षण करना चाहते हैं, तो आपको DI को सेटअप करने की आवश्यकता है और IDepartmentAppService का परीक्षण करने के लिए सभी आवश्यक निर्भरताएं IDepartmentAppService

टेस्ट फिक्सचर के माध्यम से DI का उपयोग करना:

public class DependencySetupFixture
{
    public DependencySetupFixture()
    {
         var serviceCollection = new ServiceCollection();
         serviceCollection.AddDbContext<SharedServicesContext>(options => options.UseInMemoryDatabase(databaseName: "TestDatabase"));
         serviceCollection.AddTransient<IDepartmentRepository, DepartmentRepository>();
         serviceCollection.AddTransient<IDepartmentAppService, DepartmentAppService>();

         ServiceProvider = serviceCollection.BuildServiceProvider();
    }

    public ServiceProvider ServiceProvider { get; private set; }
}

public class DepartmentAppServiceTest : IClassFixture<DependencySetupFixture>
{
    private ServiceProvider _serviceProvide;

    public DepartmentAppServiceTest(DependencySetupFixture fixture)
    {
        _serviceProvide = fixture.ServiceProvider;
    }

    [Fact]
    public async Task Get_DepartmentById_Are_Equal()
    {
        using(var scope = _serviceProvider.CreateScope())
        {   
            // Arrange
            var context = scope.ServiceProvider.GetServices<SharedServicesContext>();
            context.Department.Add(new Department { DepartmentId = 2, DepartmentCode = "123", DepartmentName = "ABC" });
            context.SaveChanges();

            var departmentAppService = scope.ServiceProvider.GetServices<IDepartmentAppService>();

            // Act
            var departmentDto = await departmentAppService.GetDepartmentById(2);

            // Arrange
            Assert.Equal("123", departmentDto.DepartmentCode);           
        }
    }
}

यूनिट टेस्ट के साथ निर्भरता इंजेक्शन का उपयोग करना अच्छा विचार नहीं है और आपको इससे बचना चाहिए। वैसे यदि आप निर्भरता दर्ज करने के लिए अपने आप को दोहराना नहीं चाहते हैं, तो आप अपने DI कॉन्फ़िगरेशन को किसी अन्य वर्ग में लपेट सकते हैं और उस वर्ग का उपयोग कहीं भी कर सकते हैं जो आप चाहते हैं।

Startup.cs के माध्यम से DI का उपयोग करना:

public class IocConfig
{
    public static IServiceCollection Configure(IServiceCollection services, IConfiguration configuration)
    {
         serviceCollection
            .AddDbContext<SomeContext>(options => options.UseSqlServer(configuration["ConnectionString"]));
         serviceCollection.AddScoped<IDepartmentRepository, DepartmentRepository>();
         serviceCollection.AddScoped<IDepartmentAppService, DepartmentAppService>();
         .
         .
         .

         return services;
    }
}

Startup क्लास और IocConfig सिर्फ IocConfig क्लास का इस्तेमाल करें:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
         IocConfig.Configure(services, configuration);

         services.AddMvc();
         .
         .
         .

यदि आप IocConfig क्लास का उपयोग नहीं करना चाहते हैं, तो Startup क्लास में ConfigureServices बदलें:

public IServiceCollection ConfigureServices(IServiceCollection services)
{
     .
     .
     .
     return services;

और परीक्षण परियोजना में IocConfig या Startup क्लास का पुन: उपयोग करें:

public class DependencySetupFixture
{
    public DependencySetupFixture()
    {
          var builder = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", false, true));
         configuration = builder.Build();

         var services = new ServiceCollection();

         // services = IocConfig.Configure(services, configuration)
         // or
         // services = new Startup(configuration).ConfigureServices(services);

         ServiceProvider = services.BuildServiceProvider();
    }

    public ServiceProvider ServiceProvider { get; private set; }
}

और परीक्षण विधि में:

[Fact]
public async Task Get_DepartmentById_Are_Equal()
{
    using (var scope = _serviceProvider.CreateScope())
    {
        // Arrange
        var departmentAppService = scope.ServiceProvider.GetServices<IDepartmentAppService>();

        // Act
        var departmentDto = await departmentAppService.GetDepartmentById(2);

        // Arrange
        Assert.Equal("123", departmentDto.DepartmentCode);
    }
}

नीचे दिए गए कस्टम वेब एप्लिकेशन फैक्ट्री और ServiceProvider.GetRequiredService का उपयोग करें, उत्तर को संपादित करने और अनुकूलन करने के लिए स्वतंत्र महसूस करें

CustomWebApplicationFactory:

public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureAppConfiguration((hostingContext, configurationBuilder) =>
        {
            var type = typeof(TStartup);
            var path = @"C:\\OriginalApplication";

            configurationBuilder.AddJsonFile($"{path}\\appsettings.json", optional: true, reloadOnChange: true);
            configurationBuilder.AddEnvironmentVariables();
        });

        // if you want to override Physical database with in-memory database
        builder.ConfigureServices(services =>
        {
            var serviceProvider = new ServiceCollection()
                .AddEntityFrameworkInMemoryDatabase()
                .BuildServiceProvider();

            services.AddDbContext<ApplicationDBContext>(options =>
            {
                options.UseInMemoryDatabase("DBInMemoryTest");
                options.UseInternalServiceProvider(serviceProvider);
            });
        });
    }
}

जोड़ने का परीक्षण:

public class DepartmentAppServiceTest : IClassFixture<CustomWebApplicationFactory<OriginalApplication.Startup>>
{
    public CustomWebApplicationFactory<OriginalApplication.Startup> _factory;
    public DepartmentAppServiceTest(CustomWebApplicationFactory<OriginalApplication.Startup> factory)
    {
        _factory = factory;
        _factory.CreateClient();
    }

    [Fact]
    public async Task ValidateDepartmentAppService()
    {      
        using (var scope = _factory.Server.Host.Services.CreateScope())
        {
            var departmentAppService = scope.ServiceProvider.GetRequiredService<IDepartmentAppService>();
            var dbtest = scope.ServiceProvider.GetRequiredService<ApplicationDBContext>();
            dbtest.Department.Add(new Department { DepartmentId = 2, DepartmentCode = "123", DepartmentName = "ABC" });
            dbtest.SaveChanges();
            var departmentDto = await departmentAppService.GetDepartmentById(2);
            Assert.Equal("123", departmentDto.DepartmentCode);
        }
    }
}

संसाधन:

https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2

https://fullstackmark.com/post/20/painless-integration-testing-with-aspnet-core-web-api





xunit