سؤال

لذلك، كنت أقرأ مدونة اختبار Google، وكانت تقول إن الحالة العالمية سيئة وتجعل من الصعب كتابة الاختبارات.أعتقد ذلك - من الصعب اختبار الكود الخاص بي الآن.فكيف أتجنب الدولة العالمية؟

أكبر الأشياء التي أستخدم الحالة العالمية (كما أفهمها) هي إدارة الأجزاء الرئيسية من المعلومات بين بيئات التطوير والقبول والإنتاج لدينا.على سبيل المثال ، لدي فئة ثابتة تسمى "Globals" مع عضو ثابت يسمى "DBConnectionString". عند تحميل التطبيق ، يحدد سلسلة الاتصال التي يجب تحميلها ، وتملأ Globals.DBConnectionString.أقوم بتحميل مسارات الملفات وأسماء الخوادم والمعلومات الأخرى في فئة Globals.

تعتمد بعض وظائفي على المتغيرات العالمية.لذلك، عندما أقوم باختبار وظائفي، يجب أن أتذكر تعيين قيم عالمية معينة أولاً وإلا ستفشل الاختبارات.أود تجنب هذا.

هل هناك طريقة جيدة لإدارة معلومات الدولة؟(أم أنني أفهم الحالة العالمية بشكل غير صحيح؟)

هل كانت مفيدة؟

المحلول

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

من الصعب تجنب بعض الحالات العالمية، ولكن أفضل طريقة للقيام بذلك هي استخدام فئات المصنع على أعلى مستوى من تطبيقك، وكل شيء أقل من هذا المستوى الأعلى يعتمد على حقن التبعية.

فائدتان رئيسيتان:أولاً، الاختبار أسهل كثيرًا، وثانيًا، تطبيقك مقترن بشكل فضفاض أكثر.أنت تعتمد على القدرة على البرمجة مقابل واجهة الفصل بدلاً من تنفيذها.

نصائح أخرى

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

يمكنك النظر في استخدام إطار عمل حقن التبعية مثل Castle Windsor ولكن في الحالات البسيطة، قد تتمكن من اتباع نهج منتصف الطريق مثل:

public interface ISettingsProvider
{
    string ConnectionString { get; }
}

public class TestSettings : ISettingsProvider
{        
    public string ConnectionString { get { return "testdatabase"; } };
}

public class DataStuff
{
    private ISettingsProvider settings;

    public DataStuff(ISettingsProvider settings)
    {
        this.settings = settings;
    }

    public void DoSomething()
    {
        // use settings.ConnectionString
    }
}

في الواقع، من المرجح أن تقرأ من ملفات التكوين في التنفيذ الخاص بك.إذا كنت مستعدًا لذلك، فإن إطار عمل DI الكامل مع التكوينات القابلة للتبديل هو الطريق المناسب ولكن أعتقد أن هذا أفضل على الأقل من استخدام Globals.ConnectionString.

السؤال الأول عظيم.

الجواب القصير:تأكد من أن تطبيقك عبارة عن وظيفة من جميع مدخلاته (بما في ذلك المدخلات الضمنية) إلى مخرجاته.

المشكلة التي تصفها لا تبدو وكأنها حالة عالمية.على الأقل حالة غير قابلة للتغيير.بل إن ما تصفه يبدو مثل ما يُشار إليه غالبًا باسم "مشكلة التكوين"، ولها عدد من الحلول.إذا كنت تستخدم Java، فقد ترغب في البحث في أطر عمل حقن خفيفة الوزن مثل غيس.في Scala، يتم حل هذا عادةً باستخدام ضمنا.في بعض اللغات، ستتمكن من تحميل برنامج آخر لتكوين البرنامج الخاص بك في وقت التشغيل.هذه هي الطريقة التي اعتدنا عليها لتكوين الخوادم المكتوبة بلغة Smalltalk، وأنا أستخدم مدير نوافذ مكتوبًا بلغة Haskell يسمى Xmonad وملف تكوينه هو مجرد برنامج Haskell آخر.

مثال على حقن التبعية في إعداد MVC، إليك ما يلي:

Index.php

$container = new Container();
include_file('container.php');

حاوية.php

container.add("database.driver", "mysql");
container.add("database.name","app");

...

$container.add(new Database($container->get('database.driver', "database.name")), 'database');
$container.add(new Dao($container->get('database')), 'dao');
$container.add(new Service($container->get('dao')));
$container.add(new Controller($container->get('service')), 'controller');

$container.add(new FrontController(),'frontController');

يستمر ملف Index.php هنا:

$frontController = $container->get('frontController');
$controllerClass = $frontController->getController($_SERVER['request_uri']);
$controllerAction = $frontController->getAction($_SERVER['request_uri']);
$controller = $container->get('controller');
$controller->$action();

وهناك ، يعتمد وحدة التحكم على كائن طبقة الخدمة الذي يعتمد على كائن DAO (كائن الوصول إلى البيانات) والذي يعتمد على كائن قاعدة البيانات مع برنامج تشغيل قاعدة البيانات ، والاسم وما إلى ذلك

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top