الفرق بين المراجعتين لصفحة: «Refactoring/replace exception with test»

من موسوعة حسوب
أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE: استبدال استثناءات بالاختبارات (Replace Exception with Test)}}</noinclude> == المشكلة == إطلاق استث...'
 
ط مراجعة وتدقيق.
 
(مراجعة متوسطة واحدة بواسطة مستخدم واحد آخر غير معروضة)
سطر 1: سطر 1:
<noinclude>{{DISPLAYTITLE: استبدال استثناءات بالاختبارات (Replace Exception with Test)}}</noinclude>  
<noinclude>{{DISPLAYTITLE: استبدال الاستثناءات بالاختبارات (Replace Exception with Test)}}</noinclude>  
== المشكلة ==
== المشكلة ==
إطلاق استثناء حيث يمكن لاختبار بسيط أن يقوم بهذا.
إطلاق استثناء يمكن لاختبار بسيط أن يحل محله.


== الحل ==
== الحل ==
سطر 9: سطر 9:


==== قبل إعادة التصميم ====
==== قبل إعادة التصميم ====
في لغة Java:<syntaxhighlight lang="java">
معالجة الاستثناء الحاصل عند وقوع الفهرس <code>periodNumber</code> خارج حدود مصفوفة القيم <code>values</code> وإعادة القيمة 0 آنذاك:
 
في لغة [[Java]]:<syntaxhighlight lang="java">
double getValueForPeriod(int periodNumber) {
double getValueForPeriod(int periodNumber) {
   try {
   try {
سطر 17: سطر 19:
   }
   }
}
}
</syntaxhighlight>في لغة C#‎:<syntaxhighlight lang="c#">
</syntaxhighlight>في لغة [[C#]]‎:<syntaxhighlight lang="c#">
double GetValueForPeriod(int periodNumber)  
double GetValueForPeriod(int periodNumber)  
{
{
سطر 29: سطر 31:
   }
   }
}
}
</syntaxhighlight>في لغة PHP:<syntaxhighlight lang="php">
</syntaxhighlight>في لغة [[PHP]]:<syntaxhighlight lang="php">
function getValueForPeriod($periodNumber) {
function getValueForPeriod($periodNumber) {
   try {
   try {
سطر 37: سطر 39:
   }
   }
}
}
</syntaxhighlight>في لغة Python:<syntaxhighlight lang="python">
</syntaxhighlight>في لغة [[Python]]:<syntaxhighlight lang="python">
def getValueForPeriod(periodNumber):
def getValueForPeriod(periodNumber):
     try:
     try:
سطر 43: سطر 45:
     except IndexError:
     except IndexError:
         return 0
         return 0
</syntaxhighlight>في لغة [[TypeScript]]:<syntaxhighlight lang="typescript">
getValueForPeriod(periodNumber: number): number {
  try {
    return values[periodNumber];
  } catch (ArrayIndexOutOfBoundsException e) {
    return 0;
  }
}
</syntaxhighlight>
</syntaxhighlight>


==== بعد إعادة التصميم ====
==== بعد إعادة التصميم ====
في لغة Java:<syntaxhighlight lang="java">
استعمال شرط بسيط ينوب مكان التعبير <code>try/catch</code> الذي يعالج الاستثناء المحتمل وقوعه:
 
في لغة [[Java]]:<syntaxhighlight lang="java">
double getValueForPeriod(int periodNumber) {
double getValueForPeriod(int periodNumber) {
   if (periodNumber >= values.length) {
   if (periodNumber >= values.length) {
سطر 53: سطر 65:
   return values[periodNumber];
   return values[periodNumber];
}
}
</syntaxhighlight>في لغة C#‎:<syntaxhighlight lang="c#">
</syntaxhighlight>في لغة [[C#]]‎:<syntaxhighlight lang="c#">
double GetValueForPeriod(int periodNumber)  
double GetValueForPeriod(int periodNumber)  
{
{
سطر 62: سطر 74:
   return values[periodNumber];
   return values[periodNumber];
}
}
</syntaxhighlight>في لغة PHP:<syntaxhighlight lang="php">
</syntaxhighlight>في لغة [[PHP]]:<syntaxhighlight lang="php">
function getValueForPeriod($periodNumber) {
function getValueForPeriod($periodNumber) {
   if ($periodNumber >= count($this->values)) {
   if ($periodNumber >= count($this->values)) {
سطر 69: سطر 81:
   return $this->values[$periodNumber];
   return $this->values[$periodNumber];
}
}
</syntaxhighlight>في لغة Python:<syntaxhighlight lang="python">
</syntaxhighlight>في لغة [[Python]]:<syntaxhighlight lang="python">
def getValueForPeriod(self, periodNumber):
def getValueForPeriod(self, periodNumber):
     if periodNumber >= len(self.values):
     if periodNumber >= len(self.values):
         return 0
         return 0
     return self.values[periodNumber]
     return self.values[periodNumber]
</syntaxhighlight>في لغة [[TypeScript]]:<syntaxhighlight lang="typescript">
getValueForPeriod(periodNumber: number): number {
  if (periodNumber >= values.length) {
    return 0;
  }
  return values[periodNumber];
}
</syntaxhighlight>
</syntaxhighlight>


سطر 79: سطر 98:
يجب استخدام الاستثناءات لمعالجة السلوك غير الاعتيادي المتعلق بخطأ غير متوقع. ولا يجب أن تكون بديلًا للاختبارات. وإذا أمكن تجنب الاستثناء بمجرد التحقق من شرطٍ ما قبل التشغيل، فافعل ذلك. ويجب الاحتفاظ بالاستثناءات للأخطاء الحقيقية.
يجب استخدام الاستثناءات لمعالجة السلوك غير الاعتيادي المتعلق بخطأ غير متوقع. ولا يجب أن تكون بديلًا للاختبارات. وإذا أمكن تجنب الاستثناء بمجرد التحقق من شرطٍ ما قبل التشغيل، فافعل ذلك. ويجب الاحتفاظ بالاستثناءات للأخطاء الحقيقية.


فعلى سبيل المثال، إذا دخلت حقل ألغام وأطلقت لغمًا هناك، مما أدى إلى إطلاق استثناء؛ وتم التعامل بنجاح مع الاستثناء وتم رفعك في الهواء إلى بر الأمان خارج حقل الألغام. لكن كان بإمكانك تجنب كل هذا بمجرد قراءة علامة التحذير أمام حقل الألغام.
فعلى سبيل المثال، افترض أنَّك دخلت حقل ألغام وأطلقت لغمًا هناك، مما أدى إلى إطلاق استثناء؛ وتم التعامل بنجاح مع الاستثناء وتم رفعك في الهواء إلى بر الأمان خارج حقل الألغام. أتعلم أنه بإمكانك تجنب كل هذا بمجرد قراءة علامة التحذير أمام حقل الألغام؟! بالتأكيد قراءة اللافتة هي الأفضل والأسهل.


== فوائد تطبيق الحل ==
== فوائد تطبيق الحل ==
* في بعض الأحيان، يمكن أن تكون شَرطية بسيطة أكثر وضوحًا من شيفرة معالجة الاستثناء.
* في بعض الأحيان، يمكن أن يكون شرط بسيطة أكثر وضوحًا من شيفرة معالجة الاستثناء.


== آلية الحل ==
== آلية الحل ==
# إنشاء شرطية لحالة حدية ونقلها قبل كتلة try/catch.
# إنشاء شرطية لحالة حدية ونقلها قبل كتلة <code>try/catch</code>.
# نقل الشيفرة من قسم <code>catch</code> داخل هذه الشرطية.
# نقل الشيفرة من قسم <code>catch</code> داخل هذه الشرطية.
# في قسم <code>catch</code>، ضع الشيفرة لإطلاق استثناء غير مسمى عادي وشغِّل كل الاختبارات.
# في قسم <code>catch</code>، ضع الشيفرة لإطلاق استثناء غير مسمى عادي وشغِّل كل الاختبارات.
# وإذا لم تُطلق استثناءات خلال الاختبارات، تخلص من العامل <code>try/catch</code>.
# وإذا لم تُطلق استثناءات خلال الاختبارات، تخلص من التعبير <code>try/catch</code>.


== انظر أيضًا ==
== انظر أيضًا ==
سطر 94: سطر 113:


== مصادر ==
== مصادر ==
* [https://refactoring.guru/replace-exception-with-test صفحة توثيق تقديم التوكيد في موقع refactoring.guru].
* [https://refactoring.guru/replace-exception-with-test صفحة توثيق استبدال الاستثناءات بالاختبارات في موقع refactoring.guru].
[[تصنيف:Refactoring]]
[[تصنيف:Refactoring]]
[[تصنيف:Refactoring Techniques]]
[[تصنيف:Refactoring Techniques]]
[[تصنيف:Simplifying Method Calls]]
[[تصنيف:Refactoring Simplifying Method Calls]]

المراجعة الحالية بتاريخ 08:36، 26 فبراير 2019

المشكلة

إطلاق استثناء يمكن لاختبار بسيط أن يحل محله.

الحل

يستعاض عن الاستثناء باختبار الحالة.

مثال

قبل إعادة التصميم

معالجة الاستثناء الحاصل عند وقوع الفهرس periodNumber خارج حدود مصفوفة القيم values وإعادة القيمة 0 آنذاك:

في لغة Java:

double getValueForPeriod(int periodNumber) {
  try {
    return values[periodNumber];
  } catch (ArrayIndexOutOfBoundsException e) {
    return 0;
  }
}

في لغة C#‎:

double GetValueForPeriod(int periodNumber) 
{
  try 
  {
    return values[periodNumber];
  } 
  catch (IndexOutOfRangeException e) 
  {
    return 0;
  }
}

في لغة PHP:

function getValueForPeriod($periodNumber) {
  try {
    return $this->values[$periodNumber];
  } catch (ArrayIndexOutOfBoundsException $e) {
    return 0;
  }
}

في لغة Python:

def getValueForPeriod(periodNumber):
    try:
        return values[periodNumber]
    except IndexError:
        return 0

في لغة TypeScript:

getValueForPeriod(periodNumber: number): number {
  try {
    return values[periodNumber];
  } catch (ArrayIndexOutOfBoundsException e) {
    return 0;
  }
}

بعد إعادة التصميم

استعمال شرط بسيط ينوب مكان التعبير try/catch الذي يعالج الاستثناء المحتمل وقوعه:

في لغة Java:

double getValueForPeriod(int periodNumber) {
  if (periodNumber >= values.length) {
    return 0;
  }
  return values[periodNumber];
}

في لغة C#‎:

double GetValueForPeriod(int periodNumber) 
{
  if (periodNumber >= values.Length) 
  {
    return 0;
  }
  return values[periodNumber];
}

في لغة PHP:

function getValueForPeriod($periodNumber) {
  if ($periodNumber >= count($this->values)) {
    return 0;
  }
  return $this->values[$periodNumber];
}

في لغة Python:

def getValueForPeriod(self, periodNumber):
    if periodNumber >= len(self.values):
        return 0
    return self.values[periodNumber]

في لغة TypeScript:

getValueForPeriod(periodNumber: number): number {
  if (periodNumber >= values.length) {
    return 0;
  }
  return values[periodNumber];
}

لم إعادة التصميم؟

يجب استخدام الاستثناءات لمعالجة السلوك غير الاعتيادي المتعلق بخطأ غير متوقع. ولا يجب أن تكون بديلًا للاختبارات. وإذا أمكن تجنب الاستثناء بمجرد التحقق من شرطٍ ما قبل التشغيل، فافعل ذلك. ويجب الاحتفاظ بالاستثناءات للأخطاء الحقيقية.

فعلى سبيل المثال، افترض أنَّك دخلت حقل ألغام وأطلقت لغمًا هناك، مما أدى إلى إطلاق استثناء؛ وتم التعامل بنجاح مع الاستثناء وتم رفعك في الهواء إلى بر الأمان خارج حقل الألغام. أتعلم أنه بإمكانك تجنب كل هذا بمجرد قراءة علامة التحذير أمام حقل الألغام؟! بالتأكيد قراءة اللافتة هي الأفضل والأسهل.

فوائد تطبيق الحل

  • في بعض الأحيان، يمكن أن يكون شرط بسيطة أكثر وضوحًا من شيفرة معالجة الاستثناء.

آلية الحل

  1. إنشاء شرطية لحالة حدية ونقلها قبل كتلة try/catch.
  2. نقل الشيفرة من قسم catch داخل هذه الشرطية.
  3. في قسم catch، ضع الشيفرة لإطلاق استثناء غير مسمى عادي وشغِّل كل الاختبارات.
  4. وإذا لم تُطلق استثناءات خلال الاختبارات، تخلص من التعبير try/catch.

انظر أيضًا

مصادر