Integration Testing برای تست APi وب

Integration Testing یکی از بهترین انواع تست ها برای APi می باشد، در این مطلب قصد داریم درباره Integration Testing و پیاده سازی آن صحبت کنیم.

 Integration Testing برای تست APi وب

قبل از این که بخواهیم درباره Integration Testing صحبت کنیم اجازه دهید مقدمه ای را برای شما بیاوریم.

اگر شما از فریم ورک های جاوا اسکریپت مانند انگولار و یا ری اکت استفاده می کنید نیاز دارید که هر صفحه وب خود را با فراخوانی API تست کنید تا مطمئن شوید به خوبی کار می کند.

شما همیشه قبل از آن که بخواهید از API خود استفاده کنید باید آن را تست کنید که به درستی کار کند، این نوع تست می تواند گزینه مناسبی برای شما برای انجام این کار باشد. یونیت تست ها می توانند گزینه مناسبی برای کدهایی باشند که دارای یک سطح واحد هستند، اما چگونه می توانید کدهای خود را در یک محیط وابسته به داده های آزمایشی تست کنید؟

فریم ورک هایی هستند که این کار را برای شما انجام می دهند ولی کار کردن با آن ها نمی تواند گزینه مناسبی برای شما در تمامی شرایط باشد.

شما همیشه می توانید یک محیط جدید را ایجاد کنید اما برای آن نیازمند پایگاه داده آزمایشی هستید.

پس راه حل چیست؟ به نظر من استفاده از این تست می تواند بهترین گزینه باشد که در ادامه درباره آن صحبت خواهیم کرد.


ساخت یک سرور مجازی

اولین مرحله برای Integration Testing این است که شما ابتدا اقدام به ساخت یک سرور مجازی برای خود کنید. من زمانی که برای اولین بار این موضوع را شنیدم بسیار هیجان زده شدم.

با داشتن یک ASP.NET Core 2.1 و یا نسخه بالاتر آن شما می توانید یک سرور مجازی بسازید که با استفاده از آن اقدام به Integration Testing برای API خود کنید.

من زمانی این موضوع را متوجه شدم که جعبه ابزار ویژوال استودیو را در یکی از برنامه های تلویزیونی که توسط Chris Woodruff اجرا می شد مشاهده کردم که به خوبی توضیح می داد که چگونه می توان با استفاده از هسته ASP.NET اقدام به ساخت API های وب کرد.

بعد از آن تصمیم گرفتم که آن را بیشتر بررسی کنم و جزئیات بیشتری را درباره این تست بدست بیاورم، با مراجعه به وب سایت doc.microsoft.com موفق شدم که اطلاعات زیادی را در این زمینه به دست بیاورم.

موارد پایه ای آن در یک کلاس جدید که Web Application Factory نامیده می شد ساخته شده بودند، این موضوع به شما اجازه می دهد تا موارد موجود برای راه اندازی در پروژه API خود را برداشته و از آن ها برای Integration Testing استفاده کنید.

این کلاس حتی این قابلیت را دارد که از پایگاه داده Entity Framework In Memory استفاده کند تا نتیجه Integration Testing را به شما بازگرداند.

 Integration Testing


راه اندازی پروژه

برای حل این مشکل شما باید پروژه API و همینطور یک یونیت تست را در دسترس داشته باشید.

در پروژه یونیت تست خود یک پوشه جدید با نام Integration Testing ایجاد کنید.

علاوه بر این من یک پوشه Infrastrast برای سرور خود نیز ایجاد کردم.

TestHost.cs قطعه ای از سرور Integration Testing است که برخی از مفاهیم جالب را به شما نمایش می دهد.

 Integration Testing


کدهای مربوط به Unit Test Project 1\Infrastructure\Test Host.cs

using System;

using APIIntegrationDemo;

using APIIntegrationDemo.Context;

using Microsoft.AspNetCore.Hosting;

using Microsoft.AspNetCore.Mvc.Testing;

using Microsoft.EntityFrameworkCore;

using Microsoft.Extensions.DependencyInjection;

using Microsoft.Extensions.Logging;

namespace UnitTestProject1.Infrastructure

{

    public class TestHost<TStartup> : WebApplicationFactory<Startup>

    {

       protected override void ConfigureWebHost(IWebHostBuilder builder)

       {

           builder.ConfigureServices(services =>

           {

               // Create a new service provider.

               var serviceProvider = new ServiceCollection()

                    .AddEntityFrameworkInMemoryDatabase()

                   .BuildServiceProvider();


               // Add a database context (AppDbContext) using an in-memory database for testing.

                services.AddDbContext<DisneyContext>(options =>

               {

                    options.UseInMemoryDatabase("IntegrationTests");

                    options.UseInternalServiceProvider(serviceProvider);

               });


                // Build the service provider.

               var sp = services.BuildServiceProvider();


               // Create a scope to obtain a reference to the database contexts

               using (var scope = sp.CreateScope())

               {

                   var scopedServices = scope.ServiceProvider;

                   var context = scopedServices.GetRequiredService<DisneyContext>();


                   var logger = scopedServices.GetRequiredService<ILogger<TestHost<TStartup>>>();


                   // Ensure the database is created.

                    context.Database.EnsureCreated();


                   try

                   {

                       // Seed your [fake] database with some specific test data.

                        context.SeedFakeDatabase();

                   }

                   catch (Exception ex)

                   {

                       logger.LogError(ex, "An error occurred seeding the " +

                                           "database with test messages. Error: {ex.Message}");

                   }

               }

           });

       }

    }

}

 Integration Testing



توضیحاتی درباره قطعه کد بالا

ابتدا با اضافه کردن یک DbContext موجود پایگاه داده In Memory را آماده می کنیم، این در واقع context پروژه شما است. حال که ما DbContext را در اختیار داریم می توانیم پایگاه داده In Memory خود را بسازیم و داده های آزمایشی آن را جمع آوری کنیم. بعد از آن که بانک اطلاعاتی خود را با استفاده از داده های آزمایشی به سرعت پر کردیم که این داده ها از طریق رشته های resource فراهم شده اند، ما در حال حاضر سرور خود را به صورت آماده در اختیار داریم.

همین؟ واقعا همین؟

بله درست است با همین اقدامات تقریبا شما بیشتر کار را انجام داده اید.

 Integration Testing

Integration Testing ما شبیه به چه چیزی است؟

Integration Testing ما در حال حاضر تنها نیازمند یک هاست آزمایشی و یک فراخوانی API واقعی است.

using System.Collections.Generic;

using System.Net.Http;

using System.Threading.Tasks;

using APIIntegrationDemo;

using APIIntegrationDemo.Entities;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using Newtonsoft.Json;

using UnitTestProject1.Infrastructure;


namespace UnitTestProject1.IntegrationTests

{

    [TestClass]

    public class AttractionApiTest

    {

       private TestHost<Startup> _server;

       private HttpClient _client;


       [TestInitialize]

       public void AttractionApiTestSetup()

        {

           _server = new TestHost<Startup>();

           _client = _server.CreateClient();

       }


       [TestCategory("Integration")]

       [TestMethod]

       public async Task GetTwoAttractionsTest()

       {

           // Arrange

            var httpResponse = await _client.GetAsync("/api/Attraction");


           // MUST be successful.

            httpResponse.EnsureSuccessStatusCode();


           // Act

           var stringResponse = await httpResponse.Content.ReadAsStringAsync();

           var attractions = JsonConvert.DeserializeObject<List<Attraction>>(stringResponse);


           // Assert

           Assert.IsNotNull(attractions);

           Assert.IsTrue(attractions.Count == 2);

       }

    }

}

زمانی که ما پاسخ را از کنترلر خود دریافت می کنیم ما رشته ها را به اشیا خودمان deserialize می کنیم بنابراین می توانیم در ادامه از آن ها در برنامه خود استفاده کنیم. حال شما می توانید هر فعلی را در API خود با استفاده از Integration Testing کنید که از جمله این افعال میتوان به GET، POST، PUT و DELETE اشاره کرد. این کار باعث می شود تا Integration Testing شما برای استفاده در API بسیار راحت تر باشد.


نتیجه گیری درباره Integration Testing

من بسیار دوست دارم که تکنیک هایی را پیدا کنم که تست های مربوط به وب را به راحت ترین شکل ممکن انجام دهد و برنامه های شما را بیشتر تحت فشار قرار دهد تا شما بتوانید با استفاده از آن ها برنامه های باثبات تر و مطمئن تری را بنویسید. توجه داشته باشید که هیچ دلیل منطقی وجود ندارد که برنامه های شما حتما در این نوع تست با شکست رو به رو شوند. این موضوع می تواند دلیل محکم برای شما باشد تا به سمت هسته  ASP.NET حرکت کنید چرا که وب در حال تبدیل شدن به یک API سیار قدرتمند است.