مطالب
آموزش QUnit #1
مقدمه:
تست و آزمایش کد برنامه‌ها و وب سایت‌هایمان، بهترین راه کاهش خطا و مشکلات آنها بعد از انتشار است. از جمله روش‌های موجود، تست واحد است که ویژوال استادیو نیز از آن برای پروژه‌های دات نت پشتیبانی می‌کند. با افزایش روز افزون کتابخانه‌های جاوا اسکریپتی و جی کوئری، نیاز به تست کد‌های جاواسکریپتی نیز بیشتر به نظر می‌رسد و بهتر است تست واحد و آزمایش شوند. اما برخلاف کدهای #C و ASP.NET تست کد‌های جاوا اسکریپت، مخصوصا زمانی که به دستکاری عناصر DOM می‌پردازیم و یا رویداد‌های درون صفحه وب را با استفاده از جی کوئری می‌نویسیم، حتی اگر در فایل جداگانه‌ای نوشته شود، این بدان معنی نیست که آماده تست واحد است و ممکن است امکان نوشتن تست وجود نداشته باشد.
بنابراین چه چیزی یک تست واحد است؟ در بهترین حالت توابعی که مقداری را برمی گردادنند، بهترین حالت برای تست واحد است. اما در بیشتر موارد شما نیاز دارید تا تاثیر کد را بر روی عناصر صفحه نیز مشاهد نمایید.
ساخت تست واحد
برای تست پذیری بهتر، توابع جاوا اسکریپت و هر کد دیگری، آن را می‌بایست طوری بنویسید که مقادیر تاثیر گذار در اجرای تابع به عنوان ورودی تابع در نظر گرفته شده باشند و همیشه نتیجه به عنوان خروجی تابع برگردانده شود؛ قطعه کد زیر را در نظر بگیرید:
 function prettyDate(time){
    var date = new Date(time || ""),
      diff = (((new Date()).getTime() - date.getTime()) / 1000),
      day_diff = Math.floor(diff / 86400);
 
    if ( isNaN(day_diff) || day_diff < 0 || day_diff >= 31 )
      return;
 
    return day_diff == 0 && (
        diff < 60 && "just now" ||
        diff < 120 && "1 minute ago" ||
        diff < 3600 && Math.floor( diff / 60 ) +
          " minutes ago" ||
        diff < 7200 && "1 hour ago" ||
        diff < 86400 && Math.floor( diff / 3600 ) +
          " hours ago") ||
      day_diff == 1 && "Yesterday" ||
      day_diff < 7 && day_diff + " days ago" ||
      day_diff < 31 && Math.ceil( day_diff / 7 ) +
        " weeks ago";
  }
تابع pertyDate اختلاف زمان حال را نسبت به زمان ورودی، بصورت یک رشته برمی گرداند. اما در اینجا مقدار زمان حال، در خط سوم، در خود تابع ایجاد شده است و در صورتی که بخواهیم برای چندین مقدار آن را تست کنیم زمان حال متفاوتی در نظر گرفته می‌شود و حداکثر، زمان 31 روز قبل را نمایش داده و در بقیه تاریخ ها undefined را بر می‌گرداند. برای تست واحد، چند تغییر می‌دهیم.
بهینه سازی، مرحله اول:
پارامتری به عنوان مقدار زمان جاری برای تابع در نظر می‌گیریم و تابع را جدا کرده و در یک فایل جداگانه قرار می‌دهیم. فایل prettydate.js بصورت زیر خواهد شد.
function prettyDate(now, time){
  var date = new Date(time || ""),
    diff = (((new Date(now)).getTime() - date.getTime()) / 1000),
    day_diff = Math.floor(diff / 86400);
 
  if ( isNaN(day_diff) || day_diff < 0 || day_diff >= 31 )
    return;
 
  return day_diff == 0 && (
      diff < 60 && "just now" ||
      diff < 120 && "1 minute ago" ||
      diff < 3600 && Math.floor( diff / 60 ) +
        " minutes ago" ||
      diff < 7200 && "1 hour ago" ||
      diff < 86400 && Math.floor( diff / 3600 ) +
        " hours ago") ||
    day_diff == 1 && "Yesterday" ||
    day_diff < 7 && day_diff + " days ago" ||
    day_diff < 31 && Math.ceil( day_diff / 7 ) +
      " weeks ago";
}
حال یک تابع برای تست داریم، چند تست واحد واقعی می‌نویسیم
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Refactored date examples</title>
  <script src="prettydate.js"></script>
  <script>
  function test(then, expected) {
    results.total++;
    var result = prettyDate("2013/01/28 22:25:00", then);
    if (result !== expected) {
      results.bad++;
      console.log("Expected " + expected +
        ", but was " + result);
    }
  }
  var results = {
    total: 0,
    bad: 0
  };
  test("2013/01/28 22:24:30", "just now");
  test("2013/01/28 22:23:30", "1 minute ago");
  test("2013/01/28 21:23:30", "1 hour ago");
  test("2013/01/27 22:23:30", "Yesterday");
  test("2013/01/26 22:23:30", "2 days ago");
  test("2012/01/26 22:23:30", undefined);
  console.log("Of " + results.total + " tests, " +
    results.bad + " failed, " +
    (results.total - results.bad) + " passed.");
  </script>
</head>
<body>
 
</body>
</html>
در کد بالا یک تابع بدون استفاده از Qunit برای تست واحد نوشته ایم که با آن تابع prettyDate را تست می‌کند. تابع test مقدار زمان حال و رشته خروجی را گرفته  و آن را با تابع اصلی تست می‌کند در آخر تعداد تست ها، تست‌های شکست خورده و تست  های پاس شده گزارش داده می‌شود.
خروجی می‌تواند مانند زیر باشد:

Of 6 tests, 0 failed, 6 passed.
Expected 2 day ago, but was 2 days ago. 
f 6 tests, 1 failed, 5 passed.

مطالب
Microbenchmark
What Is Micro Benchmark? Micro benchmark is a benchmark designed to measure the performance of a very small and specific piece of code. (^)
البته این موضوع امروزه بیشتر در Java مطرحه تا دات نت (^ و ^ و ^) اما مفاهیم اصلی مختص یک زبان یا پلتفرم نیست.
وقتی در مورد آزمایش بار برای مقایسه کارایی کلاس StrigBuilder تحقیق میکردم به مطلب جالبی برخورد کردم. خلاصش این میشه که برای تست بار قسمتهایی از کدتون میتونین زمان موردنیاز برای اجرای اون کد رو بررسی کنین و چون ممکنه انجام این کار چندین بار نیاز بشه بهتره از متد زیر برای اینکار استفاده کنین:
static void Profile(string description, int iterations, Action func) {
    // clean up
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();

    // warm up 
    func();

    var watch = Stopwatch.StartNew();
    for (int i = 0; i < iterations; i++) {
        func();
    }
    watch.Stop();
    Console.Write(description);
    Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
}
سه خط اول متد بالا برای آماده‌سازی حافظه جهت اجرای تست موردنظر است. برای آشنایی بیشتر با نحوه عملکرد Garbage Collector (^ و ^ و ^) خوندن کتاب فوق العاده CLR via C# - 3rd ed رو پیشنهاد میکنم (فصلهای 21 و 22).
سپس یکبار اکشن موردنظر (که حاوی قطعه کد موردنظره) اجرا میشه تا مسائل مربوطه به بارگذاری‌های اولیه در نتیجه تست تاثیر نزاره (warm up).
در نهایت هم آزمایش بار برای تعداد تکرار درخواست شده انجام میشه و زمان اجرای اون در خروجی چاپ میشه.
برای استفاده از متد فوق میشه از کد زیر استفاده کرد:
Profile("a descriptions", how_many_iterations_to_run, () =>
{
   // ... code being profiled
});
و برای استفاده از این متد در آزمایش کارایی کلاس StringBuilder میشه از کدی شبیه به کد زیر استفاده کزد:
var iterations = 10000000;
var testString = ".NET Tips is awesme!";
do
{
  var sb1 = new StringBuilder(testString);
  var sb2 = new StringBuilder(testString) { Capacity = testString.Length * iterations };
  try
  {
    Profiler.Profile("StringBuilder Profiler", iterations, () => sb1.Append(testString));
    Profiler.Profile("StringBuilder Capacity Profiler", iterations, () => sb2.Append(testString));
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex.Message);
  }
  finally
  {
    Console.WriteLine("----------------------------------------------------------------");
    sb1.Clear();
    sb2.Clear();
  }
} while (Console.ReadKey(true).Key == ConsoleKey.C); // C = continue
البته برای اینکه عملیات مقدار دهی خاصیت Capacity در قسمت warm up متد profile نتایج رو تحت تاثیر قرار نده برای این تست من اون قسمت رو کامنت کردم (اگر این کار رو نکنین زمانهای بدست اومده برای هر دو مورد یکی خواهد بود). اجرای کد بالا نتایج زیر رو تو سیستم من ارائه داد:

می‌بینین که نتایج استفاده از متد موردبحث کمی فرق داره و افزایش کارایی در حالت استفاده از پراپرتی Capacity دیگه حدود 3 برابر نیست و حدود 2 دو برابره. البته زمان بدست اومده برای هر دو مورد نسبت به قبل کاهش داشته که بیشترش میتونه مربوطه به عدم درنظر گرفتن زمان موردنیاز برای ایجاد کلاس StringBuilder در این تست جدید باشه (چون بعید میدونم عملیات پاکسازی حافظه توسط GC تو این تست تاثیر چندانی داشته باشه). درهر حال نتایج این تست بیشتر به واقعیت نزدیکه!
اشتراک‌ها
مسیر راه Bootstrap

Starting today, Bootstrap 3 will move to end of life, and will no longer receive critical security updates.

Bootstrap 4 moved to Long Term Support release on February 14, 2019 and will no longer receive new features. It will continue to receive bug fixes, security updates, and documentation updates.

Bootstrap 5 is under active development. You can follow our progress on GitHub. 

مسیر راه Bootstrap
اشتراک‌ها
jQuery 3.6.0 منتشر شد

jQuery 3.6.0 has been released! In jQuery 3.5.0, the major change was a security fix for the html prefilter. This release does not include a security fix, but does have some good bug fixes and improvements. We still have our eyes on a jQuery 4.0 release, but until then we will continue to support the 3.x branch and address important issues. 

jQuery 3.6.0 منتشر شد
نظرات مطالب
Blogger auto poster
سلام . دستت درد نکنه . عالیه . فقط 3 تا سؤال : 1 -  نوع فرمت زمان ارسال لینکها بصورت 12 ساعته است و یا 24 ساعته است ؟ ( یعنی 10 شب از نظر برنامه 22 تعریف شده است و یا 10 )
2- برنامه  بصورت خودکار همیشه تمام لینکهای شر شده در یک روز را منتشر میکند و یا یک تعداد مشخصی را ؟ ( اگر مورد اول درست هست بهتر است که مورد دوم را در نسخه جدید برنامه به آن اضافه کنید )
 3- چرا بعد از انجام تنظیمات برنامه با توجه به حساب کاربری خودم و اتصال موفق ، بعد از زدن دکمه Download News در میان لیست لینکهای شر شده من ، لیست لینکها منتشر شده و منتخب شما مشاهده میگردد ؟ . آیا آدرس فید شما بصورت پیش فرض در برنامه گنجانده شده است ؟: ببینید :

http://upload20.ir/upload/13207696341013548167.jpg
مطالب
آشنایی با پلاگین TickTack برای Mask ورودی کاربر

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

برای آشنایی با نوشتن Plugin در jQuery، می‌توان مباحث پیشین این سایت را دنبال کرد.(  JQuery Plugins #1  و  JQuery Plugins #2)


jQueryTickTack Plugin   :

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

ویژگی‌های این Plugin عبارتند از:

1- تنظیم زمان پیش فرض

2- کنترل حداقل و حداکثر زمان وارد شده

3- تغییر ساعت و دقیقه بوسیله کلید‌های جهتی بالا و پایین

4- تغییر انتخاب ساعت و دقیقه بوسیله کلید‌های جهتی چپ و راست

5- تغییر ساعت و دقیقه بوسیله فشردن اعداد روی صفحه کلید


چگونگی استفاده از این Plugin

ابتدا کتابخانه jQuery و این پلاگین را به صفحه خود اضافه نمایید و سپس کدهای زیر را برای استفاده از این Plugin اضافه نمایید: 

        jQuery(document).ready(function () {
            $("#TextBox1").TickTack();
            $("#TextBox2").TickTack({
                 initialTime: '8:44',
                minHour: 8,
                minMinute: 0,
                maxHour: 22,
                maxMinute: 40
            });
        });
در ادامه به بررسی تنظیمات انجام شده در این پلاگین می‌پردازیم:

initialTime : زمان اولیه جهت نمایش به کاربر (حتما بایستی ساعت و دقیقه بوسیله : از یکدیگر جداشوند)

minHour : حداقل ساعت ورودی

minMinute : حداقل دقیقه ورودی

maxHour : حداکثر ساعت ورودی

maxMinute : حداکثر دقیقه ورودی

 

پس از انجام این تنظیمات و اجرا کردن برنامه،TextBox شما به صورت زیر نمایش داده  می‌شود: 

پس از انتخاب TextBox، قسمت ساعت به صورت پیش فرض انتخاب می‌شود و کاربر باید ساعت مد نظر را وارد کند؛ در اینجا، عدد اول ساعت، مد نظر است.

برای نمونه در اینجا عدد 2 توسط کاربر وارد می‌شود؛ پس از ورود عدد و با توجه به تنظیمات انجام شده، ساعت به صورت اتوماتیک به حداکثر مقداری که می‌تواند بپذیرد تغییر می‌کند (در این مثال چون کاربر عدد 2 را وارد کرده و در تنظیمات انجام شده حداکثر ساعت دریافتی 22 و حداکثر دقیقه 40 تعریف شده است،  ساعت به صورت پیشفرض به 22:40 تغییر می‌یابد)

و پس از وارد کردن عدد دوم ساعت توسط کاربر مکان نما به قسمت دقیقه منتقل می‌شود که در این جا عدد اول دقیقه مد نظر است

وارد کردن عدد 3 برای دقیقه
 

وارد کردن عدد دوم دقیقه  

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

در ادامه دوستان علاقمند لطفا جهت بهبود کیفیت کار، باگ و یا مشکلات کدنویسی را اطلاع دهند.

با تشکر