في اليوم الآخر ، كتبت اختبارات لوحدة تتفاعل مع قاعدة بيانات. لم أكن أرغب في ربط وحدة الاختبار بقاعدة البيانات - وهذا يخلق متطلبات إضافية للبيئة حيث سيتم إجراء الاختبار. لا أرغب في إنشاء مثيلات من sql. اكتب الصفوف مع اللوحات اللازمة مرة واحدة - بالنسبة لي هذا النوع هو "الصندوق الأسود" ، وأود أن يظل هكذا. البحث في الموضوع أيضا لم يجد أي شيء مثير للاهتمام.
أردت مشاركة اكتشافاتي مع المجتمع: في التوزيع الرئيسي لـ Go ، هناك أداة جاهزة تقريبًا لمثل هذه الاحتياجات: تسمى FakeDb.
ماذا يمكن أن تفعل هذه الأداة؟
في جوهرها ، هذه هي أبسط قاعدة بيانات ، ولكنها تعمل بكامل طاقتها ككائن DB ، وقادرة على إنشاء الجداول ، وملءها ، وجعل عينات بسيطة منها. جميع الجداول التي تم إنشاؤها مؤقتة وموجودة طالما كان مثيل FakeDb موجودًا. بالإضافة إلى ذلك ، تتوفر محاكاة المضاهاة عند استدعاء استثناء أمر ومضاهاة.
أوامر FakeDb
تتكون الأوامر من عبارات مفصولة بشريط عمودي - |. العبارة هي إما كلمة أساسية أو تعبير عن النموذج "key = value". حيث المفتاح هو اسم العمود.
تمسحها
يقوم الأمر بتدمير الجداول وإرجاع نتيجة فارغة. بالإضافة إلى ذلك ، إنه تحقق من عدم وجود مأزق.
مثال الاتصال:
WIPE
CREATE
يقوم الأمر بإنشاء جدول بالأعمدة المحددة من النوع المحدد.
تنسيق الاتصال:
CREATE|_|1=,...,N=
الأنواع المدعومة:
- منطقي
- nullbool - منطقية أو فارغة
- int32
- سلسلة
- nullstring - string أو NULL
- int64
- nullint64 - int64 أو NULL
- float64
- nullfloat64 - float64 أو NULL
- التاريخ والوقت
- أي - واجهة فارغة ، أي نوع
مثال الاتصال:
CREATE|people|name=string,age=int32,photo=any,dead=bool,bdate=datetime
INSERT
يضيف الأمر صفوفًا إلى الجدول الذي تم إنشاؤه.
تنسيق الاتصال:
INSERT|_|1=,...,N
فيما يلي ، يمكن تعيين القيمة بثلاث طرق:
- حدد قيمة بشكل صريح ، على سبيل المثال
123
. - أشر إلى "؟" ، وتمرير القيمة كمعلمة.
- حدد "؟ Parameter_name" وقم بتمرير القيمة إلى المعلمة المسماة.
مثال الاتصال:
INSERT|people|name=Alice,age=?,photo=?photo
SELECT
يسمح لك الأمر بتحديد إما كل صفوف الجدول ، أو مع بعض التحديد.
تنسيق الاتصال:
SELECT|_|1,...,N| SELECT|_|1,...,N|1=?,...,M
مثال الاتصال:
SELECT|categories|category_id,category_parent_id,category_name| SELECT|categories|category_id,category_parent_id,category_name|category_parent_id=?parent
والنتيجة هي نسخة كاملة من sql.Rows.
WAIT
يحاكي التأخير في تنفيذ الأمر. يجب أن تضاف قبل أي أمر أعلاه.
تنسيق الاتصال:
WAIT||
يشار إلى التأخير على أنه كمية وكمية بديلة تشير إلى وحدة القياس: s - ثانية ، n - نانوثانية ، u - مايكروثانية ، h - ساعات ، وما إلى ذلك (يتم استخدام وظيفة (time.ParseDuration ())).
مثال الاتصال:
WAIT|1s|SELECT|categories|category_id,category_parent_id,category_name|
هلع
يلقي استثناء عند استدعاء أمر.
تنسيق الاتصال:
PANIC|_|
سيتم وضع قيمة MethodName في الحقل stmt.panic
(اكتب fakeStmt).
مثال الاتصال:
PANIC|blablabla|SELECT|categories|category_id,category_parent_id,category_name|
استخدام
تم إنشاء FakeDb لاختبار الحزمة "sql" للتسليم الرئيسي كبرنامج نصي للاختبار . لم أجدها في حزمة منفصلة. لذلك ، اخترتها بنفسي في حزمة ووضعتها هنا: gihub .
كانت التعديلات الطفيفة مطلوبة لإبراز الحزمة.
مثال للاستخدام
package packname import ( "fmt" "testing" "io/ioutil" "database/sql" "github.com/a1div0/fakedb" ) func TestFoo(t *testing.T) { fc := &fakedb.FakeConnector{ } db := sql.OpenDB(fc) if db.Driver() != fakedb.Fdriver { t.Error("OpenDB should return the driver of the Connector") return } if _, err := db.Exec("WIPE"); err != nil { t.Error("exec wipe: %v", err) } defer db.Close() db.Exec("CREATE|users|user_email=string,user_id=int64") db.Exec("INSERT|users|user_email=?,user_id=?", "test@email.com", 345) rows, err := db.Query( "SELECT|users|user_id|user_email=?email", sql.Named("email", user_email), ) if err != nil { t.Error(err) } result, err := Foo(rows)
شكرا لاهتمامكم
ملاحظة: يرجى كتابة التعليقات - هل تستخدم محاكاة قاعدة البيانات في الاختبارات؟ إذا كان الأمر كذلك ، أي حزمة؟