خانه / Test / شناخت SUT پیش شرط لازم و ضروری برای نوشتن تست‌ خوب

شناخت SUT پیش شرط لازم و ضروری برای نوشتن تست‌ خوب

The “system under test”. It is short for “whatever thing we are testing” and is always defined from the perspective of the test.

xUnit Test Patterns, Refactoring Test Code

Gerard Meszaros

هر چند از نظر عملی ممکن است شدنی باشد که تمامی فرآیندهای یک سیستم را تحت یک تست مورد آرمون قرار داد (اگر به این مورد فکر می‌کنید مراقب باشید!) اما ما معمولا یک مورد کاربرد(use case) را در نظر میگیریم ویژگی‌های مربوط به آن را مشخص میکنیم. سپس سناریوهای مربوط به هر ویژگی‌ها را مشخص می‌کنیم: سناریوها می‌توانند:

  • سناریوهای Happy Path
  • سناریوهای Negative Path
  • سناریوهای Exceptional Path

باشند.

هر کدام از این سناریوها، در شرایط مشخص و قابل کنترل(context) یک رفتاری از یک بخش از سیستم را تریگر می‌کنند و انتظار خروجی متناسب را از آن بخش از سیستم دارند(Context > Action > Outcome). آن بخشی از سیستم Action بر روی آن انجام می‌شود به عنوان System-Under Test یا به اختصار SUT میشناسیم.

توجه داشته باشید که SUT همیشه از نقطه نظر تست به آن بخش از سیستم که زیر تست قرار می‌گیرد اطلاق می‌شود.

عدم شناخت و درک صحیح SUT می‌تواند منجر به نوشتن تست‌های شکننده(fragile tests)شود. همچنین اصلی‌ترین دلیل استفاده بیش‌از حد و نابجا از مشابه‌سازی (Test Doubles) وابستگی‌های SUT بدلیل همین عدم شناحت و درک SUT در تست کیس‌ها می‌باشد. تست‌هایی که بیش از یک سناریو را تست می‌کنند از دیگر عوارض عدم شناخت مناسب SUT می‌باشد.

فرض کنید سناریو زیر را داریم: OrderService که دارای سرویسی جهت لغو کردن یک سفارش دارد. پس از لغو سفارش توسط مشتری، ضمن تغییر وضعیت سفارش به لغو شده باید به مشتری اطلاع رسانی لازم انجام شود.

public class OrderService
    {
        private readonly IOrderRepository _orderRepository;
        private readonly INotificationService _notificationService;
        public OrderService(IOrderRepository orderRepository, 
INotificationService notificationService)
        {
            _orderRepository = orderRepository;
            _notificationService = notificationService;
        }

        public void Cancel(OrderId orderId)
        {
            var order  = _orderRepository.Get(orderId);
            
     order.Cancel();
            _notificationService.SendNotification(_customerId);
        }
    }

با توجه به اینکه قصد نوشتن تست برای فرآیند کنسل کردن سفارش را داریم، System-Under Test در اینجا OrderService می‌باشد. پس از تشخیص SUT می‌توان بسته به سناریوی هر تست کیس براحتی  نسبت به مشابه سازی وابستگی‌های مورد نظر SUT اقدام کرد. دو تست کیس برای این مورد می‌توان در نظر گرفت.

سناریوی اول پس از لغو سفارش، باید وضعیت سفارش به لغو شده تغییر پیدا کند. در این سناریو با توجه به اینکه قصد تست کردن ارسال نوتیفیکیشن به مشتری را نداریم، می‌توانیم به کمک Dummy Object این سرویس را به راحتی مشابه سازی کرد. به دلیل اینکه این سرویس در انتهای متد Cancel مورد استفاده قرار می‌گیرد، نمی‎‌توان آنرا null در نظر گرفت و باید از Null Object استفاده کرد.

[Fact]
        public void CancelAnOrder_OrderStatus_ChangedToCanceled()
        {
            var orderRepository = new OrderRespositorySpy();
            var nullNotificationService = new NullNotificationService();
            var orderId = new OrderId("100");

            var sut = new OrderService(orderRepository , nullNotificationService);

            sut.Cancel(orderId);

            Assert.Equal(null , _orderRepository.Get(orderId));
        }


تست کیس دیگر، تست کردن این است که آیا پس از حذف سفارش، به مشتری اطلاع می‌شود یا خیر؟ قصد استفاده از پیاده سازی واقعی سرویس و ارسال(ایمیل یا پیامک) به مشتری را نداریم. در این تست کیس باید این مورد بررسی شود که آیا سرویس Cancel در Order به درستی و با پارامترهای صحیح سرویس NotificationService را صدا می‌زند یا حیر؟ در اینجا باید سرویس INotificationService را Mock کرده و در فاز fixture آنرا setup کرده و در نهایت آنرا verify کنیم. IOrderRepository را نیز می‌توان براحتی Stub کرد.

        [Fact]
        public void CancelAnOrder_SendNotificationToCustomer_Notified()
        {
            var orderRepository = new OrderRespositoryStub();
            var mockNotificationService = new MockNotificationService();

            //Setup the expected interaction of the SUT with its DOC
            mockNotificationService.Setup(...);

            var sut = new OrderService(orderRepository , mockNotificationService);
            var orderId = new OrderId("100");
            sut.Cancel(orderId);

            //Verify the expected interaction of the SUT with its DOC 
            mockNotificationService.Verify();
        }

درباره ی Masoud Bahrami

همچنین ببینید

Software Behavior and Architecture

جدال ناتمام معماران نرم افزار و مدیران ذینفع سازمان مقدمه یکی از جدال ها و …

اجایل به معنی اسکرام نیست!

اجایل به معنی اسکرام نیست! گزاره ای به ظاهر بدیهی و روشن؛ در عمل اما خلاف …

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

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

به کانال من در تلگرام بپیوندید

اگر علاقمند به مباحث معماری و مدلسازی نرم افزار هستید می توانید به کانال تلگرام بپیوندید.

پیوستن بستن