السخرية من التبعية مع التركيب التلقائي
-
21-12-2019 - |
سؤال
لقد بدأت مؤخرا باستخدام أوتوفيكستوري + أوتوموك وأنا أحاول إنشاء مثيل من Func<IDbConnection>
(أي مصنع اتصال).
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var connectionFactory = fixture.Create<Func<IDbConnection>>();
يبدو أن هذا يعمل بشكل جيد:
- نظام بلدي تحت الاختبار يمكن استدعاء المندوب وسوف تحصل على وهمية من
IDbConnection
- التي يمكنني الاتصال بها بعد ذلك
CreateCommand
, ، والتي سوف تحصل لي وهمية منIDbCommand
- التي يمكنني الاتصال بها بعد ذلك
ExecuteReader
, ، والتي سوف تحصل لي وهمية منIDataReader
أريد الآن إجراء إعدادات إضافية على وهمية IDataReader
, ، مثل جعله يعود true
عندما Read()
يسمى.
من ما قرأته ، يجب أن أستخدم Freeze
لهذا:
var dataReaderMock = fixture.Freeze<Mock<IDataReader>>();
dataReaderMock.Setup(dr => dr.Read())
.Returns(true);
هذا لا يبدو لتلبية توقعاتي على الرغم من.عندما أتصل IDbCommand.ExecuteReader
, ، سأحصل على قارئ مختلف عن القارئ الذي جمدته/أعده للتو.
هنا مثال:
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var dataReaderMock = fixture.Freeze<Mock<IDataReader>>();
dataReaderMock.Setup(dr => dr.Read())
.Returns(true);
//true - Create<IDataReader> retrieves the data reader I just mocked
Assert.AreSame(dataReaderMock.Object, fixture.Create<IDataReader>());
//false - IDbCommand returns a different instance of IDataReader
Assert.AreSame(dataReaderMock.Object, fixture.Create<IDbCommand>().ExecuteReader());
ماذا أفعل خطأ?كيف يمكنني الحصول على تركيبات أخرى ، مثل IDbCommand
, ، لاستخدام مثيل سخر من IDataReader
?
المحلول
اعتبارا من 3.20.0 ، يمكنك استخدام AutoConfiguredMoqCustomization
.سيؤدي هذا تلقائيا إلى تكوين جميع الاستهزاء بحيث يتم إنشاء قيم إرجاع أعضائها عن طريق التثبيت التلقائي.
على سبيل المثال., IDbConnetion.CreateCommand
سيتم تكوينه تلقائيا لإرجاع ملف IDbCommand
من المباراة ، و IDbCommand.ExecuteReader
سيتم تكوينه تلقائيا لإرجاع ملف IDataReader
من المباراة.
كل هذه الاختبارات يجب أن تمر الآن:
var fixture = new Fixture().Customize(new AutoConfiguredMoqCustomization());
var dataReaderMock = fixture.Freeze<Mock<IDataReader>>();
dataReaderMock.Setup(dr => dr.Read())
.Returns(true);
//all pass
Assert.Same(dataReaderMock.Object, fixture.Create<IDataReader>());
Assert.Same(dataReaderMock.Object, fixture.Create<IDbCommand>().ExecuteReader());
Assert.Same(dataReaderMock.Object, fixture.Create<IDbConnection>().CreateCommand().ExecuteReader());
Assert.Same(dataReaderMock.Object, fixture.Create<Func<IDbConnection>>()().CreateCommand().ExecuteReader());
نصائح أخرى
عليك أن Freeze
ال Mock<IDbCommand>
كذلك-وإعداد الكائن وهمية (كما كعب) لإرجاع القائمة dataReaderMock.Object
على سبيل المثال.
إذا قمت بإضافة ما يلي إلى مرحلة ترتيب الاختبار ، فسوف يمر الاختبار:
var dbCommandStub =
fixture
.Freeze<Mock<IDbCommand>>()
.Setup(x => x.ExecuteReader())
.Returns(dataReaderMock.Object);
في حين أن الحل من نيكوس يعمل وأود أن لا أنا لا أوصي السخرية ado.net.
في رأيي ، من المحتمل أن يكون من الصعب فهم اختباراتك والحفاظ عليها ولن تمنحك الثقة التي يجب أن توفرها لك اختباراتك.
وأود أن تنظر في اختبار طبقة البيانات الخاصة بك عن طريق الذهاب على طول الطريق إلى قاعدة البيانات على الرغم من أنه أبطأ.
أوصي بقراءة هذه المقالة فيما يتعلق بأفضل الممارسات للسخرية:http://codebetter.com/jeremymiller/2006/01/10/best-and-worst-practices-for-mock-objects/
لا تسخر من الآخرين:http://aspiringcraftsman.com/2012/04/01/tdd-best-practices-dont-mock-others/
لا أعرف وضعك بالضبط ولكن على أي حال أردت مشاركة هذا.