برنامه نویسی

آزمون های واحد نباید در ارزیابی کدنویسی شما باشد

من برای مدت طولانی در مورد این موضوع سکوت کرده ام. ولی الان میخوام برم کمربندت رو ببند…

در چند هفته گذشته تجربیاتی با تست های واحد در طول ارزیابی های کدگذاری داشته ام که باعث عصبانیت و عصبانیت من شده است. این اولین بار نیست که با این نوع مسائل مواجه می شوم. اما بالاخره آنقدر خسته شدم که با صدای بلند و با افتخار اعلام کنم که:

آزمون‌های واحد نباید جایی در ارزیابی‌های کدگذاری که بر روی داوطلبان احتمالی اعمال می‌کنید، داشته باشند.

ممکن است برای برخی از شما بدعت به نظر برسد. (راهنمایی: من اهمیتی نمی دهم.) اما اگر واقعاً شما را آزار می دهد که بسیار، احتمال زیادی وجود دارد که شما بخشی از مشکل باشید.

توضیحات تصویر

من بدعت گذار نیستم

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

بنابراین البته شما باید آن را در تمام ارزیابی های کدنویسی خود لحاظ کنید… درست؟؟؟

نه

اجازه بده توضیح بدم…

توضیحات تصویر

نوشتن تست باعث اتلاف وقت می شود و می تواند بی احترامی به داوطلب باشد

در طول عملیات عادی روزانه در محیط برنامه‌نویس شما، معمولاً برای کسی غیرقابل قبول است که بگوید: “من این کار را تمام کردم و کار را ارائه کردم – اما هیچ تست واحدی ننوشتم زیرا وقتم تمام شد.” در طول “عملیات توسعه دهنده” معمولی، یک کار در واقع انجام نمی شود انجام شده تا زمانی که آزمایش مناسب را در نظر نگیرید. اما این استاندارد باید نه در طول ارزیابی های کدگذاری اعمال شود.

اکثر ارزیابی های کدنویسی زمان بندی شده هستند. آنها یک دوره زمانی تعیین می کنند که در آن شما باید یک باگ را برطرف کنید یا یک ویژگی بسازید یا یک ویژگی موجود را به نحوی تغییر دهید. اغلب، این محدودیت های زمانی می تواند دلهره آور باشد – حتی برای توسعه دهندگان ارشد.

تصور کنید یک ساعت فرصت دارید تا یک ویژگی را در React بسازید. شاید اینطور نباشد که سخت. شاید شما کاملاً مطمئن هستید که می توانید این را از بین ببرید. اما در میانه ساختن آن، با آن برخورد می کنید مقداری نوعی اشکال میدونی… اونجوری که چند دقیقه اونجا میشینی و فقط فکر میکنی: “صبر کن… در جریان“شاید فراموش کرده اید یک کنترل کننده کلید را وصل کنید و کمی طول می کشد تا متوجه شوید چه چیزی را نادیده گرفته اید. شاید فقط اشتباه تایپی احمقانه ای انجام داده اید که بلافاصله در IDE شما آشکار نمی شود. صرف نظر از این، نکته این است که، حتی در ساده ترین کار، گاهی اوقات می توانید 10 تا 15 دقیقه “سوزانید” چیزی را که خراب کرده اید را اصلاح کنید.

در نهایت، شما ثابت آی تی. و شما به ساختن ویژگی کامل درست در مهلت ساعتی ادامه می دهید. در واقع شما آن را ساختید خوب. شما نسبت به کدی که وارد کرده اید کاملاً مطمئن هستید.

اما وقت نکردی هیچ تستی اضافه کنی…

اگر کد شما جامد است، و کار را کامل کرده اید، و درک کاملی از React نشان داده اید، هیچ راهی وجود ندارد که شما هرگز نباید صرفاً به این دلیل که این کار را انجام نداده اید، علامت گذاری کنید (یا از بحث حذف شوید). همچنین وقت داشته باشید که تست های واحد را روی محلول خود بزنید.

اجازه دهید در اینجا کاملاً واضح بگویم. عمل صرف از نوشتن یک آزمون واحد به طور کلی بسیار آسان است. اکثر چارچوب‌های تست، نحو‌های بسیار مشابهی دارند و برای کمک به شما در نوشتن تست‌ها به گونه‌ای طراحی شده‌اند که معنای معنایی داشته باشد. آنها از فعل استفاده می کنند مانند:

it('Should enqueue the items to the queue', (done) => {...});
وارد حالت تمام صفحه شوید

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

و

onDequeueSpy.calledOnce.should.be.true;
وارد حالت تمام صفحه شوید

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

بنابراین نوشتن تست‌ها به این روش (برای هر توسعه‌دهنده معتبر) باید کاملاً طبیعی باشد.

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

چند هفته پیش تست کد نویسی را انجام دادم که می خواستند آن را اضافه کنم زیاد ویژگی های یک پایگاه کد React موجود. و آنها به من گفتند که همه چیز باید انجام شود … در 45 دقیقه. فقط این نبود که باید اجزای جدیدی اضافه می کردم و همه گردانندگان رویداد را به هم متصل می کردم، بلکه باید مراقب بودم که این کار را دقیقاً انجام دهم. سبک که قبلاً در بقیه پایگاه کد وجود داشت. علاوه بر این، الزامات CSS متعددی وجود داشت که دقیقاً چگونگی راه حل را دیکته می کرد نگاه کن. بنابراین فقط به دست آوردن آن کافی نبود منطق کار کردن. من همچنین باید همه چیز را مطابقت می دادم مشخصات طراحی. و دوباره، من مجبور شدم همه این کارها را انجام دهم در 45 دقیقه.

اما البته این تمام چیزی نبود که آنها می خواستند. الزامات همچنین گفت که تمام آزمون های موجود باید قبول شوند و برای هر ویژگی اضافی که اضافه شده است باید تست های جدیدی بنویسم. و قرار بود همه این کارها را انجام دهم در 45 دقیقه. آشکارا مسخره بود.

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

اما اینها تنها مشکلات مربوط به تست های واحد در چالش های کدنویسی نیستند…

توضیحات تصویر

تست های شکسته

پس شاید شما از من نمی خواهید نوشتن تست ها شاید شما فقط یک آزمون واحد buncha در پایگاه کد دارید که باید قبل از اینکه بتوانم راه حل خود را ارسال کنم، قبول شوید؟ بنظر معقولانه میاد، درست?

خوب…

در موارد متعدد، من یک پایگاه کد جدید را باز کرده ام، که در آن قرار است راه حل جدیدی بنویسم، و متوجه شدم که تست ها موفق نمی شوند. بیرون جعبه. مسلماً، اگر “تست” این باشد که پایگاه کد حاوی یک اشکال است و تست های واحد ناموفق هستند به خاطر اون باگ، و شما اکنون از من می خواهید که آن اشکال را برطرف کنم، سپس… باشه. خوب. من آن را دریافت می کنم.

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

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

توضیحات تصویر

الزامات مخفی

اینم یکی دیگه <sarcasm>لذت بخش</sarcasm> سردردی که از آزمایش های واحد تعبیه شده شما به آن برخورد کرده ام: شما از من نمی خواهید بنویسم جدید واحد تست می کند، اما شما یک دسته کامل از آزمایش ها را در پایگاه کد بارگذاری کرده اید که برای تعیین اینکه آیا ویژگی جدیدی که من ساخته ام مطابق با مشخصات کار می کند یا خیر طراحی شده اند. بنابراین من تمام دستورالعمل ها را با دقت خواندم و راه حلی را ارائه کردم که رضایت بخش باشد تمام دستورالعمل ها، و در مرورگر به زیبایی اجرا می شود، اما من تست ها را اجرا می کنم …

و شکست می خورند.

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

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

به عنوان مثال، من به این سناریو برخورد کردم همین دیروز. وظیفه React دارای ویژگی های زیادی بود که فقط باید به صورت مشروط نمایش داده شود. مانند زمانی که API هیچ نتیجه ای برمی گرداند، باید یک “نتیجه ای یافت نشد” را نمایش دهید. <div>. اما اگر API در واقع نتایج را برگرداند، این div نباید نمایش داده شود. و من آن را برای مطابقت با این الزام کدنویسی کردم. اما آزمون باز هم شکست خورد.

چرا شکست خورد؟ از آنجا که این آزمایش به طور فوق خاص به دنبال “نتیجه نیست” بود. <div> NULL بودن. من آن را برای استفاده کدنویسی کردم display: none. شرط اولیه فقط بیان می کرد که <div> نباید باشد نمایش داده. آن هرگز اعلام کرد که در نتیجه <div> در واقع باید NULL باشد. بنابراین برای اینکه تست را قبول کنم، مجبور شدم به راه حل خود برگردم (راه حلی که کاملاً مطابق با آن بود نوشته شده است دستورالعمل ها)، و منطق را تغییر دهید NULL-خارج از <div>.

من مجبور شدم همین کار را برای چندین عنصر دیگر که منطق مشابهی داشتند انجام دهم. زیرا آن عناصر نیز تست های واحد خود را داشتند – که همگی انتظار یک مقدار صریح از آن را داشتند NULL.

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

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

توضیحات تصویر

تست های واحد غیر منطقی

شاید شما از من نمی خواهید که من را ترک کنم جدید تست های واحد، و شاید شما “الزامات محرمانه” را در تست های واحد خود پنهان نمی کنید، و شاید تمام تست های مرتبط با کد قدیمی به خوبی در خارج از جعبه کار کنند. بنابراین نباید هیچ مشکلی برای من وجود داشته باشد، درست??

امم…

دیروز داشتم یک صف ناهمزمان را در Node کدنویسی می کردم و با این gem of a test unit برخورد کردم:

it('Should dequeue items every 250ms from the queue', (done) => {
    queue.enqueue(1);
    queue.enqueue(2);
    queue.start();
    queue.getCurrentInterval().should.eql(250);
    var onDequeueSpy = sinon.spy();
    queue.on('dequeued', onDequeueSpy);
    setTimeout(() => {
        onDequeueSpy.calledOnce.should.be.true;
        onDequeueSpy.firstCall.args[0].should.eql(1);
    }, 260);
    setTimeout(() => {
        onDequeueSpy.calledTwice.should.be.true;
        onDequeueSpy.getCall(1).args[0].should.eql(2);
        done();
    }, 510);
});
وارد حالت تمام صفحه شوید

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

در اینجا آنچه این تست واحد انجام می دهد:

  1. با اضافه کردن دو آیتم به صف queue.enqueue().

  2. این فرآیند dequeuing را با queue.start().

  3. این اطمینان را ایجاد می کند که فاصله زمانی روی مقدار پیش فرض 250 میلی ثانیه تنظیم شده است.

  4. سپس 260 میلی ثانیه صبر می کند و بررسی می کند که صف فقط یک بار فراخوانی شده باشد. (این می گذرد.)

  5. سپس صبر می کند دقیقا 250 میلی ثانیه اضافی.

  6. سپس بررسی می کند که صف دقیقاً دو بار فراخوانی شده باشد.

با تنظیم زمان انتظار برای بودن دقیقا 250 میلی ثانیه بعد از اولین بررسی کنید، شرایط مسابقه ای را تنظیم می کند که به موجب آن این آزمایش به طور متناوب تقریباً 50٪ مواقع با شکست مواجه می شود.

ممکن است فکر کنید، “اما، بررسی دوم باید 510 میلی ثانیه پس از شروع صف اتفاق بیفتد، که باعث می شود صف فعال شود. دو برابراما از آنجایی که این تنها 10 میلی ثانیه آزادی عمل می دهد، منجر به سناریوهای متناوب می شود که در آن گاهی آزمون با موفقیت انجام می شود – و گاهی اوقات با شکست مواجه می شود.

البته، یک راه آسان برای “رفع” این مشکل این است که به تماس دوم کمی فضای تنفس بیشتری بدهید. اما نمی توانید فایل های تست را آپدیت کنید. اگر سعی کنید این کار را انجام دهید، git push مسدود شده است.

من با این بازی کردم زمان طولانی، تلاش می کند تا بدون تغییر فایل های آزمایشی به طور مداوم کار کند. فایده ای نداشت.

اینم جواهری دیگه از همان چالش کدنویسی:

it('Should continue to listen for new data even on pausing the dequeue process', (done) => {
    var onDequeueSpy = sinon.spy();
    var onEnqueueSpy = sinon.spy();
    queue.on('dequeued', onDequeueSpy);
    queue.start();
    queue.enqueue(2);
    queue.enqueue(3);
    queue.enqueue(4);
    queue.pause();
    setTimeout(() => {
        onDequeueSpy.callCount.should.eql(0);
        queue.start();
        queue.emit('interval', 50);
        queue.on('enqueued', onEnqueueSpy);
        queue.enqueue(95);
        queue.enqueue(110);
    }, 260);
    setTimeout(() => {
        queue.enqueue(221);
        onEnqueueSpy.callCount.should.eql(3);
        onDequeueSpy.callCount.should.eql(1);
        queue.print().should.eql([3, 4, 95, 110, 221]);
        done();
    }, 320);
});
وارد حالت تمام صفحه شوید

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

این تست در این خط با شکست مواجه می شود:

    onDequeueSpy.callCount.should.eql(1);
وارد حالت تمام صفحه شوید

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

اینجاست چرا شکست می خورد. صف است آغاز شده با مقدار پیش فرض 250 میلی ثانیه. سپس صف را متوقف می کند. سپس، در اول setTimeout()، صف را دوباره شروع می کند. و سپس این فاصله را روی 50 میلی ثانیه تنظیم می کند. اما این فاصله را تا 50 میلی ثانیه تنظیم نمی کند بعد از دوباره صف را شروع کرد و هنگامی که صف را دوباره راه اندازی می کند، در ابتدا با تاخیر 250 میلی ثانیه شروع می شود.

این بدان معناست که 250 میلی ثانیه اول باید به طور کامل اجرا شود تا تماس صف بعدی بتواند با تاخیر 50 میلی ثانیه اجرا شود.

البته مهم نیست که خود تست یونیت janky AF بود. تنها چیزی که برای ارزیاب مهم است این است که آزمون (غیرمنطقی) قبول نشد.

در نهایت، فکر می کنم خوب است که از این تست های غیرمنطقی استفاده می کنند، زیرا حدس بزنید چیست؟ من مطمئناً نمی خواهم به هر حال روی تیم برنامه نویس بی مزه آنها کار کنم. اما من هنوز هم اذیت می‌شوم چون دیروز ساعت‌ها از وقتم را برای انجام چالش‌شان تلف کردم، بعد از اینکه قبلاً یک مصاحبه زنده عالی با آنها داشتم و بعد از اینکه قبلاً کدنویسی کرده بودم. یک راه حل کاری، زیرا آنها نمی توانند برای نوشتن تست های منطقی واحد اذیت شوند.

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

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

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

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