برنامه نویسی

اجزای خود را در تست ها جدا کنید: چگونه وابستگی های خود را مسخره کنیم

قبلاً اشاره کردیم که تست های واحد به عنوان بررسی های اساسی برای اجزای برنامه ما عمل می کنند. ما همچنین نحوه نوشتن تست‌هایی را بررسی کردیم که در آن مقادیر را به یک محاسبات منتقل کردیم و خروجی‌ها را با نتایج مورد انتظار مقایسه کردیم. در این آزمایش‌ها، ما ورودی‌های نمونه خود را مستقیماً به روشی وارد کردیم که یک عدد را می‌گرفت، آن را مربع می‌کرد و سپس نتیجه را برمی‌گرداند. هیچ مؤلفه اضافی در فرآیند مورد نیاز نبود.

با این حال، همه چیز همیشه آنقدر ساده نیست.

گاهی اوقات، منطق خدمات ما به بیش از یک جزء متکی است. در واقع، معمولاً تفکیک مسئولیت ها هنگام طراحی ماژول های نرم افزار ایده خوبی است. با متمرکز نگه داشتن منطق یک ماژول بر روی یک منطقه خاص، یک هدف قابل شناسایی واحد دارد. این به نوبه خود به این معنی است که ما می‌توانیم از آن ماژول در هر کجا که لازم است، بدون نیاز به اضافه کردن ویژگی‌ها و قابلیت‌های دیگری که ممکن است فوراً مرتبط نباشند، دوباره استفاده کنیم. علاوه بر این، می‌توانیم ماژول را با معنی بیشتری نام‌گذاری کنیم و به طور بالقوه درک پایه کد را آسان‌تر می‌کنیم.

در تست واحد، ما می‌خواهیم فقط یک مؤلفه را آزمایش کنیم – نه یک گردش کار. اگر موضوع مورد آزمون وابستگی هایی داشته باشد، عمداً می خواهیم آنها را از آزمون حذف کنیم. به این ترتیب، ما دقیقاً می دانیم که در صورت بروز مشکل، تلاش های رفع اشکال خود را کجا متمرکز کنیم. یکی از راه های انجام این کار، تمسخر است.

مشکل تا اینجا

ما این سری را با این هدف شروع کردیم که بتوانیم هیپوتانوس یک مثلث را محاسبه کنیم. برای انجام این کار، باید سه کار را انجام دهیم:

  1. یک عدد را در خودش ضرب کنید تا مربع آن را پیدا کنید. ما این کار را برای دو عدد انجام می دهیم.

  2. مجموع دو مقدار بدست آمده از مرحله 1 را محاسبه کنید.

  3. جذر حاصل از مرحله 2 را پیدا کنید.

به عنوان بخشی از تکمیل مرحله 1، ما یک را ایجاد کردیم MultiplicationService که می تواند هر عدد داده شده را مربع کند. با تمرکز بر مرحله 2، بیایید یک جدید ایجاد کنیم CalculationService که:

  • دو عدد جداگانه را به عنوان مقادیر ورودی می پذیرد.

  • مربع آنها را در MultiplicationService.

  • دو نتیجه را با هم جمع می کند.

کد این کار ممکن است به شکل زیر باشد:

public class CalculationService
{
    private readonly IMultiplicationService _multiplicationService;

    public CalculationService(IMultiplicationService multiplicationService)
    {
        _multiplicationService = multiplicationService;
    }

    public int SumOfSquares(int a, int b)
    {
        int aSquared = _multiplicationService.Square(a);
        int bSquared = _multiplicationService.Square(b);
        return aSquared + bSquared;
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نوشتن آزمون

ما می توانیم آن را ببینیم SumOfSquares استفاده می کند Square از جانب MultiplicationService. برای اطمینان از اینکه ما فقط منطق را در داخل تست می کنیم SumOfSquares روش، ما می توانیم از کتابخانه ای به نام Moq برای تمسخر استفاده کنیم MultiplicationService در تست های واحد سی شارپ ما. برای این کار ابتدا یک رابط ایجاد می کنیم MultiplicationService که شامل تمام متدهای عمومی آن است:

public interface IMultiplicationService
{
    int Square(int number);
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

یک بار MultiplicationService آن را پیاده سازی می کند، ما می توانیم آزمون واحد خود را بنویسیم. اولین تلاش ممکن است به این صورت باشد:

[Test]
public void CalculationServiceCanCalculateSumOfSquares()
{
    // Arrange

    var multiplicationService = Mock.Of<IMultiplicationService>();
    var service = new CalculationService(multiplicationService);

    // Act

    var result = service.SumOfSquares(3, 4);

    // Assert

    Assert.That(result, Is.EqualTo(25));
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با این حال، اگر آن را اجرا کنیم، خواهیم دید که آزمایش با شکست مواجه خواهد شد:

Expected: 25
But was:  0
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

چرا این شکست خورد؟

اگر به آزمون خود نگاه کنیم، می‌بینیم که ما یک تمسخر ارائه کرده‌ایم IMultiplicationService. با این حال، ما آن را برای برگرداندن هیچ مقداری پیکربندی نکردیم. ما می توانیم این کار را با تغییر اندکی بیانیه انجام دهیم:

var multiplicationService = Mock.Of<IMultiplicationService>(s =>
    s.Square(3) == 9 &&
    s.Square(4) == 16);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در اینجا، ما می گوییم که:

  • وقتی زنگ میزنیم Square با 3، می خواهیم مدل ما یک مقدار را برگرداند 9.

  • وقتی زنگ میزنیم Square با 4، ما میخواهیم 16 برگردانده شود.

با انجام این کار، می توانیم مطمئن شویم که منطق در SumOfSquares درست است، حتی اگر اجرای Square تغییرات به گونه ای که نتایج آن غیر قابل اعتماد می شود. از این گذشته، در حال حاضر در حال نوشتن یک تست واحد هستیم: این تست فقط باید منطق یک جزء واحد را آزمایش کند، نه گردش کار کلی. پس از اصلاح، آزمایش ما به این صورت خواهد بود:

[Test]
public void CalculationServiceCanCalculateSumOfSquares()
{
    // Arrange

    var multiplicationService = Mock.Of<IMultiplicationService>(s =>
        s.Square(3) == 9 &&
        s.Square(4) == 16);

    var service = new CalculationService(multiplicationService);

    // Act

    var result = service.SumOfSquares(3, 4);

    // Assert

    Assert.That(result, Is.EqualTo(25));
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همانطور که در تصویر 1 نشان داده شده است، باید ببینیم که تست ما اکنون با اجرای آن با موفقیت انجام می شود.

اکسپلورر تست ویژوال استودیو که تمام تست‌های قبول شده را نشان می‌دهد

تصویر 1: آزمون CalculationServiceCanCalculateSumOfSquares قبول شد

خلاصه

هنگام نوشتن تست های واحد، می خواهید اجزای خود را به صورت مجزا آزمایش کنید. با مؤلفه‌هایی که وابستگی دارند، یکی از راه‌های محدود کردن دامنه منطق مورد آزمایش، تمسخر آن وابستگی‌ها است. در سی شارپ می توانید از Moq برای این کار استفاده کنید. هنگام ایجاد یک ماکت، می توان رفتارهای آن را مشخص کرد. به عبارت دیگر، می‌توانید آن را طوری پیکربندی کنید که هر زمان که مقدار ورودی مشخصی به آن داده شد، مقدار خاصی را برگردانید.

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


با تشکر برای خواندن!

این مجموعه با هدف پوشش دادن اصول اولیه تست نرم افزار، به شما اطمینان بیشتری نسبت به کد خود و نحوه کار با آن می دهد.

اگر این مقاله را مفید یافتید، لطفاً در خبرنامه هفتگی من ثبت نام کنید تا مقالات بیشتری مانند این را مستقیماً به صندوق ورودی شما تحویل دهید (لینک به Substack می رود).

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا