Skip to content

5. Spring IoC من الناحية العملية

سنناقش الآن، من خلال أمثلة، تطبيق ما رأيناه سابقًا عمليًّا.

5.1. المثال 1

الفئة [Personne.vb] هي كما يلي:

Namespace istia.st.springioc.demos
    Public Class Personne

         ' الحقول الخاصة
        Private _nom As String
        Private _age As Integer

         ' منشئ افتراضي
        Public Sub New()
        End Sub

         ' الخصائص المرتبطة بالحقول الخاصة
        Public Property nom() As String
            Get
                Return _nom
            End Get
            Set(ByVal Value As String)
                _nom = Value
            End Set
        End Property

        Public Property age() As Integer
            Get
                Return _age
            End Get
            Set(ByVal Value As Integer)
                _age = Value
            End Set
        End Property

         ' سلسلة الهوية
        Public Overrides Function tostring() As String
            Return String.Format("[{0},{1}]", nom, age)
        End Function

         ' طريقة init
        Public Sub init()
            Console.WriteLine("init personne {0}", Me.ToString)
        End Sub

         ' طريقة الإغلاق
        Public Sub close()
            Console.WriteLine("destroy personne {0}", Me.ToString)
        End Sub

    End Class
End Namespace

تحتوي الفئة على:

  • حقلين خاصين هما «الاسم» و«العمر» يمكن الوصول إليهما عبر خصائص
  • طريقة toString لاسترداد قيمة الكائن [Personne] في شكل سلسلة أحرف
  • طريقة init التي سيستدعيها Spring عند إنشاء الكائن، وطريقة close التي سيستدعيها عند تدمير الكائن

لإنشاء كائنات من النوع [Personne]، سنستخدم ملف Spring [spring-config-1.xml] التالي:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">

<objects>
    <object id="personne1" type="istia.st.springioc.demos.Personne, demo1" init-method="init"
        destroy-method="close">
        <property name="nom">
            <value>Simon</value>
        </property>
        <property name="age">
            <value>40</value>
        </property>
    </object>
    <object id="personne2" type="istia.st.springioc.demos.Personne, demo1" init-method="init"
        destroy-method="close">
        <property name="nom">
            <value>Brigitte</value>
        </property>
        <property name="age">
            <value>20</value>
        </property>
    </object>
</objects>

يُعرّف هذا الملف

  • يحدد كائنين للمفاتيح "personne1" و"personne2" على التوالي من النوع [Personne]
  • ويقوم بتهيئة خصائص [nom, age] لكل شخص
  • ويحدد الطرق التي يجب استدعاؤها عند الإنشاء الأولي للكائن [init-method] وعند إتلاف الكائن [destroy-method]

لإجراء اختباراتنا، سنستخدم فئات اختبار NUnit. وستكون الفئة الأولى كما يلي:

Imports System
Imports Spring.Objects.Factory.Xml
Imports System.IO
Imports NUnit.Framework
Imports istia.st.springioc.demos

Namespace istia.st.springioc.tests

    <TestFixture()> _
    Public Class NunitTestSpringIocDemo1
         ' الكائن المراد اختباره
        Private factory As XmlObjectFactory

        <SetUp()> _
        Public Sub init()
             ' يتم إنشاء مثيل من المصنع
            factory = New XmlObjectFactory(New FileStream("spring-config-1.xml", FileMode.Open))
             ' السجل
            Console.WriteLine("setup test")
        End Sub

        <Test()> _
        Public Sub demo()
             ' استرداد الكائنات [Personne] من ملف Spring باستخدام مفاتيحها
            Dim personne1 As Personne = CType(factory.GetObject("personne1"), Personne)
            Console.WriteLine("personne1=" + personne1.ToString())
            Dim personne2 As Personne = CType(factory.GetObject("personne2"), Personne)
            Console.WriteLine("personne2=" + personne2.ToString())
            personne2 = CType(factory.GetObject("personne2"), Personne)
            Console.WriteLine("personne2=" + personne2.ToString())
        End Sub

        <TearDown()> _
        Public Sub destroy()
             ' يتم تدمير الكائنات الفردية
            factory.Dispose()
             ' تحرير مورد المصنع
            factory = Nothing
             ' المتابعة
            Console.WriteLine("teardown test")
        End Sub

    End Class
End Namespace

تعليقات:

  • للحصول على الكائنات المُعرَّفة في الملف [spring-config-1.xml]، نستخدم كائنًا من النوع [XmlObjectFactory]. وهناك أنواع أخرى من «المصانع» التي تتيح الوصول إلى الكائنات الفردية في ملف التكوين. يتم الحصول على الكائن [XmlObjectFactory] في طريقة السمة [SetUp] الخاصة بفئة الاختبار ويتم تخزينه في متغير خاص. تجدر الإشارة إلى أن الطريقة المزودة بالسمة <Setup()> يتم تنفيذها قبل كل اختبار.
  • سيتم وضع الملف [spring-config-1.xml] في المجلد [bin] الخاص بالتطبيق
  • يمكن لـ Spring استخدام ملفات التكوين ذات التنسيقات المختلفة. يتيح الكائن [XmlObjectFactory] تحليل ملف تكوين بتنسيق XML.
  • يؤدي تشغيل ملف Spring إلى إنتاج كائن من النوع [XmlObjectFactory]، وهو هنا كائن المصنع. باستخدام هذا الكائن، يمكن الحصول على كائن فريد (singleton) محدد بالمفتاح C، عن طريق factory.getObject(C).
  • تقوم الطريقة [demo] باستدعاء وعرض قيمة الكائنات الفردية ذات المفتاحين "personne1" و"personne2".

هيكل مشروع Visual Studio هو كما يلي:

Image

تعليقات:

  • يُسمى المشروع VS باسم [demo1]
  • يحتوي المجلد [istia] على أكواد المصدر. ستُنقل الأكواد المُجمَّعة إلى المجلد [bin] الموجود داخل المجلد DLL [demo1.dll]:

Image

  • يوجد الملف [spring-config-1.xml] في المجلد [bin] الخاص بالمشروع.
  • يحتوي المجلد [bin] على الملفات اللازمة للتطبيق:
    • Spring.Core.dll، Spring.Core.xml لفئات Spring
    • log4net.dll لسجلات Spring
    • demo1.dll وهو ملف DLL الذي تم إنشاؤه أثناء إنشاء المشروع

يتم تحميل ملف DLL و [demo1.dll] الناتجين عن إنشاء المشروع في أداة الاختبار الرسومية [Nunit-Gui 2.2]. وتقوم هذه الأداة تلقائيًا بعرض فئات Nunit الموجودة في ملف DLL:

Image

يؤدي تنفيذ الطريقة [demo] الخاصة باختبار NUnit إلى النتائج الموضحة أعلاه والمذكورة أدناه:

***** istia.st.springioc.tests.NunitTestSpringIocDemo1.demo
setup test
init personne [Simon,40]
personne1=[Simon,40]
init personne [Brigitte,20]
personne2=[Brigitte,20]
personne2=[Brigitte,20]
destroy personne [Simon,40]
destroy personne [Brigitte,20]
teardown test

تعليقات:

  • السطر 2: يبدأ الاختبار بتنفيذ طريقة السمة <Setup()>
  • السطر 3: العملية
            Dim personne1 As Personne = CType(factory.GetObject("personne1"), Personne)

أجبرت على إنشاء البين [personne1]. ونظرًا لأننا كتبنا [init-method="init"] في تعريف الكائن الفردي [personne1]، فقد تم تنفيذ الأسلوب [init] الخاص بالكائن [Personne] الذي تم إنشاؤه. ويتم عرض الرسالة المقابلة.

init personne [Simon,40]
  • السطر 4: العملية
            Console.WriteLine("personne1=" + personne1.ToString())

أدت إلى عرض قيمة الكائن [Personne] الذي تم إنشاؤه.

personne1=[Simon,40]
  • السطران 5-6: تتكرر نفس الظاهرة بالنسبة لـ bean المفتاح [personne2].
init personne [Brigitte,20]
personne2=[Brigitte,20]
  • السطر 7: العملية الأخيرة
personne2 = CType(factory.GetObject("personne2"), Personne)
Console.WriteLine("personne2=" + personne2.ToString())

لم تسفر إلا عن سطر واحد معروض:

personne2=[Brigitte,20]

وبالتالي، لم تؤدِ إلى إنشاء كائن جديد من النوع [Personne]. لو كان الأمر كذلك، لكان قد تم عرض طريقة [init]، وهو ما لم يحدث هنا. هذا هو مبدأ الكائن الفريد (singleton). لا يقوم Spring، بشكل افتراضي، بإنشاء سوى نسخة واحدة من الكائنات (beans) الموجودة في ملف التكوين الخاص به. وهو عبارة عن خدمة مرجعية للكائنات. إذا طُلب منه مرجع كائن لم يتم إنشاؤه بعد، فإنه يقوم بإنشائه ويقدم مرجعًا له. أما إذا كان الكائن قد تم إنشاؤه بالفعل، فإن Spring يكتفي بتقديم مرجع له.

  • الأسطر 8-10: يتم تنفيذ طريقة السمة <TearDown()> (السطر 10). وفي داخلها، تتم العملية
             ' يتم تدمير الكائنات الفردية
            factory.Dispose()

إتلاف الكائنات الفردية التي أنشأها Spring. ويؤدي ذلك إلى تنفيذ طريقة كل منها [close] لأننا كتبنا، في ملف التكوين، لكل منها: "destroy-method=close". وهذا ما تشير إليه العروض التالية:

destroy personne [Simon,40]
destroy personne [Brigitte,20]

وبما أننا اكتسبنا الآن أساسيات تكوين Spring، فسنكون من الآن فصاعدًا أسرع قليلاً في شرحنا.

5.2. المثال 2

لننظر إلى الفئة الجديدة التالية [Voiture]:

Imports istia.st.springioc.demos

Namespace istia.st.springioc.demos

    Public Class Voiture
         ' الحقول الخاصة
        Private _marque As String
        Private _type As String
        Private _propriétaire As Personne

         ' الخصائص العامة
        Public Property marque() As String
            Get
                Return _marque
            End Get
            Set(ByVal Value As String)
                _marque = Value
            End Set
        End Property

        Public Property type() As String
            Get
                Return _type
            End Get
            Set(ByVal Value As String)
                _type = Value
            End Set
        End Property

        Public Property propriétaire() As Personne
            Get
                Return _propriétaire
            End Get
            Set(ByVal Value As Personne)
                _propriétaire = Value
            End Set
        End Property

         ' منشئ افتراضي
        Public Sub New()

        End Sub

         ' منشئ بثلاثة معلمات
        Public Sub New(ByVal marque As String, ByVal type As String, ByVal propriétaire As Personne)
             ' يتم تهيئة الحقول الخاصة عبر خصائصها المرتبطة
            With Me
                .marque = marque
                .type = type
                .propriétaire = propriétaire
            End With
        End Sub

         ' سلسلة تعريف كائن «السيارة»
        Public Overrides Function tostring() As String
            Return String.Format("[{0},{1},{2}]", marque, type, propriétaire.ToString)
        End Function

         ' طريقتا init وdestroy
        Public Sub init()
            Console.WriteLine("init voiture {0}", Me.ToString)
        End Sub

        Public Sub destroy()
            Console.WriteLine("destroy voiture {0}", Me.ToString)
        End Sub

    End Class
End Namespace

تحتوي الفئة على:

  • ثلاثة حقول خاصة هي _type و _marque و _propriétaire. يمكن تهيئة هذه الحقول وقراءتها من خلال الخصائص العامة. كما يمكن تهيئتها باستخدام منشئ Voiture(String, String, Personne). تحتوي الفئة أيضًا على مُنشئ بدون معلمات يسمح أولاً بإنشاء كائن [Voiture] غير مُهيأ، ثم تهيئته لاحقًا عبر خصائصه العامة.
  • طريقة toString لاسترداد قيمة الكائن [Voiture] في شكل سلسلة أحرف
  • طريقة init التي سيستدعيها Spring مباشرة بعد إنشاء الكائن، وطريقة destroy التي سيستدعيها عند تدمير الكائن

لإنشاء كائنات من النوع [Voiture]، سنستخدم ملف Spring [spring-config-2.xml] التالي:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">
<objects>
     <!-- الأشخاص -->
    <object id="personne1" type="istia.st.springioc.demos.Personne, demo1" init-method="init"
        destroy-method="close">
        <property name="nom">
            <value>Simon</value>
        </property>
        <property name="age">
            <value>40</value>
        </property>
    </object>
    <object id="personne2" type="istia.st.springioc.demos.Personne, demo1" init-method="init"
        destroy-method="close">
        <property name="nom">
            <value>Brigitte</value>
        </property>
        <property name="age">
            <value>20</value>
        </property>
    </object>
     <!-- سيارة -->
    <object id="voiture1" type="istia.st.springioc.demos.Voiture, demo1" init-method="init"
        destroy-method="destroy">
        <constructor-arg index="0">
            <value>Peugeot</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>307</value>
        </constructor-arg>
        <constructor-arg index="2">
            <ref object="personne2"/>
        </constructor-arg>
    </object>
</objects>

يضيف هذا الملف إلى التعريفات السابقة كائن مفتاح "voiture1" من النوع [Voiture]. لتهيئة هذا الكائن، كان من الممكن كتابة:

    <object id="voiture1" type="istia.st.springioc.demos.Voiture, demo1" init-method="init"
        destroy-method="destroy">
        <constructor-arg index="0">
            <value>Peugeot</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>307</value>
        </constructor-arg>
        <constructor-arg index="2">
            <ref object="personne2"/>
        </constructor-arg>
    </object>

بدلاً من اختيار هذه الطريقة التي سبق عرضها، اخترنا هنا استخدام منشئ Voiture(String, String, Personne) الخاص بالفئة. من ناحية أخرى، يحدد العنصر الفردي [voiture1] الطريقة التي يجب استدعاؤها عند الإنشاء الأولي للكائن [init-method] والطريقة التي يجب استدعاؤها عند تدمير الكائن [destroy-method].

لإجراء اختباراتنا، سنستخدم فئة الاختبار NUnit [NunitTestSpringIocDemo2] التالية:

Imports System
Imports Spring.Objects.Factory.Xml
Imports System.IO
Imports NUnit.Framework
Imports istia.st.springioc.demos

Namespace istia.st.springioc.tests

    <TestFixture()> _
    Public Class NunitTestSpringIocDemo2
         ' مصنع العناصر الفردية
        Private factory As XmlObjectFactory

        <SetUp()> _
        Public Sub init()
             ' يتم إنشاء مثيل لمصنع
            factory = New XmlObjectFactory(New FileStream("spring-config-2.xml", FileMode.Open))
             ' السجل
            Console.WriteLine("setup test")
        End Sub

        <TearDown()> _
    Public Sub destroy()
             ' يتم تدمير العناصر الفردية
            factory.Dispose()
             ' تحرير المصنع
            factory = Nothing
             ' المتابعة
            Console.WriteLine("teardown test")
        End Sub

        <Test()> _
        Public Sub demo2()
             ' استرداد الكائن الفردي [voiture1]
            Dim voiture1 As Voiture = CType(factory.GetObject("voiture1"), Voiture)
            Console.WriteLine("Voiture1=[{0}]", voiture1)
        End Sub

    End Class
End Namespace

تعليقات:

  • تظل طرق السمات <Setup()> و<TearDown()> دون تغيير.
  • تسترد الطريقة [demo2] مرجعًا إلى العنصر الفردي [voiture1] وتعرضه.

تظل بنية مشروع Visual Studio كما كانت من قبل. لم تظهر سوى فئتين جديدتين بالإضافة إلى ملف تكوين Spring:

Image

يُظهر تنفيذ الاختبار NUnit النتائج التالية:

Image

دعونا نعلق على ما يظهر على الشاشة:

1
2
3
4
5
6
7
8
***** istia.st.springioc.tests.NunitTestSpringIocDemo2.demo2
setup test
init personne [Brigitte,20]
init voiture [Peugeot,307,[Brigitte,20]]
Voiture1=[[Peugeot,307,[Brigitte,20]]]
destroy voiture [Peugeot,307,[Brigitte,20]]
destroy personne [Brigitte,20]
teardown test

التعليقات:

  • السطر 2: يتم تنفيذ طريقة السمة [Setup] قبل كل اختبار، وهنا [demo]
  • السطر 3: يبدأ Spring في إنشاء الكائن الفردي [voiture1]. وهذا الكائن يعتمد على الكائن الفردي [personne2] الذي لا وجود له. لذا يتم إنشاء هذا الأخير وتنفيذ طريقة [init] الخاصة به.
  • السطر 4: يمكن الآن إنشاء الكائن الفردي [voiture1]. ثم يتم تنفيذ طريقة [init] الخاصة به.
  • السطر 5: تعرض الطريقة [demo2] قيمة الكائن الفردي [voiture1]
  • الأسطر 6-8: يتم تنفيذ الطريقة [TearDown] الخاصة بالاختبار. يتم تدمير الكائنات الفردية، مما يؤدي إلى تنفيذ طرقها [destroy]

5.3. المثال 3

نقوم بإدخال الفئة الجديدة [GroupePersonnes] التالية:

Imports istia.st.springioc.demos

Namespace istia.st.springioc.demos

    Public Class GroupePersonnes
         ' الحقول الخاصة
        Private _membres() As Personne
        Private _groupesDeTravail As Hashtable

         ' الخصائص العامة
        Public Property membres() As Personne()
            Get
                Return _membres
            End Get
            Set(ByVal Value() As Personne)
                _membres = Value
            End Set
        End Property

        Public Property groupesDeTravail() As Hashtable
            Get
                Return _groupesDeTravail
            End Get
            Set(ByVal Value As Hashtable)
                _groupesDeTravail = Value
            End Set
        End Property

         ' منشئ افتراضي
        Public Sub New()

        End Sub

         ' سلسلة هوية الكائن GroupeDePersonnes
        Public Overrides Function tostring() As String
             ' يتم تصفح قائمة أعضاء المجموعة
            Dim identité As String = "[membres=("
            Dim i As Integer
            For i = 0 To membres.Length - 2
                identité += membres(i).ToString + ","
            Next
            identité += membres(i).ToString + "), groupes de travail=("
             ' يتم تصفح قاموس مجموعات العمل
            Dim clés As IEnumerator = groupesDeTravail.Keys.GetEnumerator
            Dim clé As Object
            While clés.MoveNext
                clé = clés.Current
                identité += String.Format("[{0},{1}] ", clé, groupesDeTravail(clé))
            End While
             ' إرجاع النتيجة
            Return identité + "]"
        End Function

         ' طرق init-destroy
        Public Sub init()
            Console.WriteLine("init GroupeDePersonnes {0}", Me.ToString)
        End Sub

        Public Sub destroy()
            Console.WriteLine("destroy GroupeDePersonnes {0}", Me.ToString)
        End Sub

    End Class
End Namespace

عضواها الخاصان هما:

_membres: جدول بأسماء أعضاء المجموعة

_groupesDeTravail: قاموس يربط شخصًا بمجموعة عمل

يتم إتاحة الوصول إلى هذه العناصر الخاصة عبر خصائص عامة. نهدف هنا إلى توضيح كيفية قيام Spring بتهيئة الكائنات المعقدة، مثل الكائنات التي تحتوي على حقول من نوع المصفوفة أو القاموس.

سيكون ملف تكوين Spring [spring-config-3.xml] كما يلي:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">
<objects>
     <!-- الأشخاص -->
    <object id="personne1" type="istia.st.springioc.demos.Personne, demo1" init-method="init"
        destroy-method="close">
        <property name="nom">
            <value>Simon</value>
        </property>
        <property name="age">
            <value>40</value>
        </property>
    </object>
    <object id="personne2" type="istia.st.springioc.demos.Personne, demo1" init-method="init"
        destroy-method="close">
        <property name="nom">
            <value>Brigitte</value>
        </property>
        <property name="age">
            <value>20</value>
        </property>
    </object>
     <!-- سيارة -->
    <object id="voiture1" type="istia.st.springioc.demos.Voiture, demo1" init-method="init"
        destroy-method="destroy">
        <constructor-arg index="0">
            <value>Peugeot</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>307</value>
        </constructor-arg>
        <constructor-arg index="2">
            <ref object="personne2" />
        </constructor-arg>
    </object>
     <!-- مجموعة من الأشخاص -->
    <object id="groupe1" type="istia.st.springioc.demos.GroupePersonnes" init-method="init"
        destroy-method="destroy">
        <property name="membres">
            <list>
                <ref object="personne1" />
                <ref object="personne2" />
            </list>
        </property>
        <property name="groupesDeTravail">
            <dictionary>
                <entry key="Brigitte">
                    <value>Marketing</value>
                </entry>
                <entry key="Simon">
                    <value>Ressources humaines</value>
                </entry>
            </dictionary>
        </property>
    </object>
</objects>
  1. تسمح العلامة <list> بتهيئة حقل من نوع المصفوفة أو من نوع IList بقيم مختلفة.
  1. تسمح العلامة <dictionary> بالقيام بنفس الشيء مع حقل ينفذ واجهة IDictionary

لإجراء اختباراتنا، سنستخدم فئة الاختبار التالية: NUnit [NunitTestSpringIocDemo3]:

Imports System
Imports Spring.Objects.Factory.Xml
Imports System.IO
Imports NUnit.Framework
Imports istia.st.springioc.demos

Namespace istia.st.springioc.tests

    <TestFixture()> _
    Public Class NunitTestSpringIocDemo3
         ' العنصر المراد اختباره
        Private factory As XmlObjectFactory

        <SetUp()> _
        Public Sub init()
             ' يتم إنشاء مثيل من المصنع
            factory = New XmlObjectFactory(New FileStream("spring-config-3.xml", FileMode.Open))
             ' سجل
            Console.WriteLine("setup test")
        End Sub

        <TearDown()> _
        Public Sub destroy()
             ' يتم تدمير العناصر الفردية
            factory.Dispose()
             ' المتابعة
            Console.WriteLine("teardown test")
        End Sub

        <Test()> _
    Public Sub demo3()
             ' استرداد الكائن الفردي [groupe1]
            Dim groupe1 As GroupePersonnes = CType(factory.GetObject("groupe1"), GroupePersonnes)
            Console.WriteLine("groupe1={0}", groupe1)
        End Sub

    End Class
End Namespace

تسترد الطريقة [demo3] العنصر الفردي [groupe1] وتعرضه.

تظل بنية مشروع Visual Studio كما كانت من قبل، باستثناء أنه يحتوي على فئتين وملف تكوين إضافيين.

Image

يؤدي تنفيذ الطريقة [demo3] في الاختبار NUnit إلى النتائج التالية:

Image

تعليقات:

***** istia.st.springioc.tests.NunitTestSpringIocDemo3.demo3
setup test
init personne [Simon,40]
init personne [Brigitte,20]
init GroupeDePersonnes [membres=([Simon,40],[Brigitte,20]), groupes de travail=([Brigitte,Marketing] [Simon,Ressources humaines] ]
groupe1=[membres=([Simon,40],[Brigitte,20]), groupes de travail=([Brigitte,Marketing] [Simon,Ressources humaines] ]
destroy GroupeDePersonnes [membres=([Simon,40],[Brigitte,20]), groupes de travail=([Brigitte,Marketing] [Simon,Ressources humaines] ]
destroy personne [Simon,40]
destroy personne [Brigitte,20]
teardown test
  • السطر 2: طريقة السمة [Setup] التي يتم تنفيذها قبل كل اختبار، وهي هنا [demo]
  • السطران 3-4: يبدأ Spring في إنشاء الكائن الفردي [groupe1]. وهذا الكائن يعتمد على الكائنات الفردية [personne1, personne2] التي لا توجد. يتم إنشاء هذه الكائنات وتنفيذ طرقها [init].
  • السطر 5: يمكن الآن إنشاء الكائن الفردي [groupe1]. ثم يتم تنفيذ طريقة [init] الخاصة به.
  • السطر 6: تعرض الطريقة [demo3] قيمة الكائن الفردي [groupe1]
  • الأسطر 7-10: يتم تنفيذ الطريقة [TearDown] الخاصة بالاختبار. يتم تدمير الكائنات الفردية، مما يؤدي إلى تنفيذ طرقها [destroy]