المفاهيم
هنفهم إيه؟ test مفيد يكتشف مشكلة قبل المستخدم ويقول لك فين السبب. هتتعلم تختار بين unit test سريع، integration test يفحص اتصال الأجزاء، و يمشي رحلة كاملة؛ ثم تتعامل مع قواعد البيانات والوقت والرسائل المتغيرة من غير اعتماد على الحظ.
قبل ما تبدأ: كل test يستدعي سلوكاً ويقارن النتيجة المتوقعة بما حدث. اعرف أساسيات method وassertion، وأن الاختبار الجيد يعزل الحالة ويعطي نتيجة قابلة للتكرار. أمثلة C# تفترض familiarity بسيطة بـ xUnit؛ المصطلحات الجديدة تتشرح قبل استخدامها.
المصطلحات اللي تحتها خط منقّط تقدر تضغط عليها لمعرفة معناها، وترجع تكمل من نفس مكانك.
#اختار الاختبار حسب المخاطرة: Pyramid و TrophyChoose tests by risk: pyramid and trophy
المطلوب من الـ tests إنك تكتشف الغلط قبل المستخدم، وتعرف سببه بسرعة. الـ unit test بيختبر سلوك صغير من غير infrastructure، والـ integration بيختبر أجزاء متوصلة ببعض، والـ بيمشي رحلة المستخدم في النظام كله.
اختبار فرامل لوحدها شبه unit test؛ تركيبها في العربية شبه integration؛ وتجربة المشوار كله شبه E2E. نجاح القطعة لوحدها مش ضمان إن التوصيلات صح.
| الشكل | التركيز | إمتى يفيد |
|---|---|---|
| Test pyramid | unit كتير، و integration أقل، و E2E قليل | domain فيه حسابات وقواعد كتير |
| Testing trophy | static checks وقاعدة كويسة من integration | تطبيق أغلب مخاطره في توصيل المكونات |
دي إرشادات مش نسب إلزامية. اختبر خصم الفاتورة بوحدات سريعة، وتخزين الطلب والدفع بـ integration، وسيب E2E لرحلات زي checkout. ماتكررش كل حالات الحساب في كل مستوى.
#Unit test واضح: AAA و FIRST و xUnit v3Readable unit tests: AAA, FIRST and xUnit v3
الـ test المفيد بيشرح قاعدة واحدة وبيفشل برسالة واضحة. معناها Arrange للمدخلات، و Act لاستدعاء السلوك، و Assert للنتيجة. FIRST: Fast، و Independent، و Repeatable، و Self-validating، و Timely. المثال كامل جوه test project بيستخدم xUnit v3، مع using Xunit;.
public static class ShippingPolicy
{
public static int Fee(int total) => total >= 1000 ? 0 : 50;
}
public sealed class ShippingTests
{
[Fact] // (1)
public void Fee_AtFreeShippingThreshold_IsZero()
{
var total = 1000; // Arrange
var fee = ShippingPolicy.Fee(total); // Act
Assert.Equal(0, fee); // Assert (2)
}
[Theory] // (3)
[InlineData(999, 50)]
[InlineData(1000, 0)]
[InlineData(1001, 0)]
public void Fee_UsesThreshold(int total, int expected) =>
Assert.Equal(expected, ShippingPolicy.Fee(total));
}
- (1) الـ Fact حالة ثابتة، والاسم بيقول السيناريو والنتيجة.
- (2) الـ assertion على نتيجة عامة، مش private method ولا تفاصيل التنفيذ.
- (3) الـ Theory بتكرر نفس السلوك ببيانات مختلفة، وبتغطي قبل الحد وعنده وبعده.
ممكن تعمل كذا assertion لنفس النتيجة المنطقية. ماتختبرش getters بسيطة لمجرد رفع coverage، وماتخليش test واحد يجرّب رحلة طويلة من سلوكيات مستقلة. راجع دليل xUnit v3 لإعداد الـ runner المناسب.
#Assertions و Test doubles: اختبر العقدAssertions and test doubles: test the contract
- خدمة إنشاء الطلب تتحقق من المخزون، تحفظ الطلب، ثم تطلب إرسال إشعار. الاختبار يحتاج يثبت قاعدة العمل، مش كل خطوة داخلية بالتفصيل.
- Stub يرجع ردًا محددًا مثل مخزون متاح؛ fake يقدم تنفيذًا مبسطًا له سلوك، مثل مستودع في الذاكرة؛ mock يتحقق من تفاعل متوقع وفق أداة الاختبار.
- اختبر السلوك الملحوظ: مخزون غير كافٍ يؤدي لرفض بلا طلب محفوظ. لو ربطت الاختبار بترتيب دوال داخلية غير مهم للعقد، refactoring صحيح قد يكسره بلا تغيير سلوك للمستخدم.
الـ assertion لازم يمسك الغلط المقصود: قيمة total، أو error محدد، أو عدم تكرار charge. الـ dummy parameter مش مستخدم؛ الـ stub بيرجّع رد جاهز؛ الـ fake تنفيذ مبسط شغال؛ الـ mock بيتحقق من interaction متوقع؛ والـ spy بيسجل calls علشان تفحصها بعدين. دي أدوار، ومكتبة واحدة ممكن تعمل أكتر من دور.
المثال مستقل في xUnit project مع packages بتاعة NSubstitute و Moq. بيعرض نفس إعداد الـ stub بالطريقتين؛ اختار واحدة في الـ test الفعلي.
using Moq;
using NSubstitute;
using Xunit;
public interface IPaymentGateway
{
bool Charge(decimal amount);
}
public sealed class Checkout(IPaymentGateway gateway)
{
public bool TryPay(decimal amount)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(amount);
return gateway.Charge(amount);
}
}
public sealed class GatewayTests
{
[Fact]
public void TryPay_WhenGatewayDeclines_ReturnsFalse()
{
var sub = Substitute.For<IPaymentGateway>();
sub.Charge(100m).Returns(false); // (1)
Assert.False(new Checkout(sub).TryPay(100m));
sub.Received(1).Charge(100m); // (2)
var mock = new Mock<IPaymentGateway>();
mock.Setup(x => x.Charge(100m)).Returns(false); // (3)
Assert.False(new Checkout(mock.Object).TryPay(100m));
mock.Verify(x => x.Charge(100m), Times.Once());
}
}
- (1) NSubstitute بيجهز نتيجة معروفة للـ boundary.
- (2) التحقق من عدد الـ calls مفيد لو العقد بيمنع دفع مكرر؛ بنتحقق إن رفض الـ gateway بيرجع للـ caller بدل نجاح وهمي.
- (3) Moq بيعمل نفس الإعداد بـ Setup و Verify.
استخدم domain objects حقيقية، وقلل verification على تفاصيل داخلية بتتغير مع refactoring. Assertions المدمجة كفاية؛ Shouldly و AwesomeAssertions بيوفروا صياغة مقروءة. FluentAssertions v8 بقى بترخيص تجاري للاستخدام التجاري؛ راجع الترخيص قبل الترقية، زي أي dependency.
#اختبار الوقت من غير Thread.SleepTest time without Thread.Sleep
اختبار انتهاء حجز مش المفروض يستنى عشر دقايق حقيقية. حقن TimeProvider بيفصل قاعدة الوقت عن ساعة الجهاز. المثال محتاج xUnit، و package Microsoft.Extensions.TimeProvider.Testing.
using Microsoft.Extensions.Time.Testing;
using Xunit;
public sealed class Booking(TimeProvider clock, DateTimeOffset expiresAt)
{
public bool IsExpired => clock.GetUtcNow() >= expiresAt; // (1)
}
public sealed class BookingTests
{
[Fact]
public void Booking_AtExpiry_IsExpired()
{
var start = new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero);
var clock = new FakeTimeProvider(start); // (2)
var booking = new Booking(clock, start.AddMinutes(10));
Assert.False(booking.IsExpired);
clock.Advance(TimeSpan.FromMinutes(10)); // (3)
Assert.True(booking.IsExpired);
}
}
- (1) السلوك بيقرأ من dependency بدل DateTime.UtcNow مباشرة.
- (2) ساعة الاختبار ليها بداية ثابتة.
- (3) بنحرك الوقت فوراً، وبنختبر الحد نفسه.
| القديم | النهج الحالي |
|---|---|
| DateTime.UtcNow و sleep | TimeProvider من 8 و FakeTimeProvider في الاختبار |
تقديم الساعة مش معناه إن كل background continuation خلصت. استنى إشارة اكتمال واضحة. ولقياس مدة، استخدم timestamp بدل ساعة الحائط اللي ممكن تتعدل.
#Integration: الـ API مع database حقيقيةIntegration: an API with a real database
اختبار controller لوحده مش هيكشف ناقص أو query مش بتترجم. WebApplicationFactory بيشغل التطبيق بـ TestServer افتراضياً من غير network socket؛ Testcontainers بيدير database مؤقتة في Docker. المثال fragment لـ test project فيه xUnit v3، و Microsoft.AspNetCore.Mvc.Testing 10، و Testcontainers.PostgreSql، و reference للـ . لازم الـ API يعرّف public partial class Program { }، ويقرأ connection string وقت تسجيل . نفترض endpoint /health بيرجع نجاح، و migrations بتتطبق بخطوة setup منفصلة قبل اختبار الداتا.
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Testcontainers.PostgreSql;
using Xunit;
public sealed class ApiFixture : IAsyncLifetime
{
private readonly PostgreSqlContainer db = new PostgreSqlBuilder()
.WithImage("postgres:17").Build();
public WebApplicationFactory<Program> App { get; private set; } = null!;
public async ValueTask InitializeAsync()
{
await db.StartAsync(); // (1)
App = new WebApplicationFactory<Program>().WithWebHostBuilder(b =>
b.UseSetting("ConnectionStrings:Default", db.GetConnectionString())); // (2)
}
public async ValueTask DisposeAsync()
{
if (App is not null) await App.DisposeAsync(); // (3)
await db.DisposeAsync();
}
}
public sealed class ApiTests(ApiFixture fixture) : IClassFixture<ApiFixture>
{
[Fact]
public async Task Health_ReturnsSuccess()
{
using var client = fixture.App.CreateClient(); // (4)
using var response = await client.GetAsync("/health");
response.EnsureSuccessStatusCode();
}
}
- (1) database تجهز قبل تشغيل الـ host؛ Docker لازم يكون متاح.
- (2) الإعداد يوجّه التطبيق للـ database المؤقتة. لو التسجيل بيعمل capture للإعداد بدري، بدّل التسجيل نفسه في ConfigureTestServices.
- (3) اقفل التطبيق قبل الـ database علشان background work مايلحقش resource مقفول.
- (4) الطلب بيمر بالـ والـ routing. نجاح health لوحده مش دليل إن حفظ الطلب شغال؛ أضف POST وتحقق من الداتا في scope جديد.
استبدل payment boundary بـ fake، لكن خليك على auth الحقيقي في اختبارات الأمان. الـ TestServer مش بيختبر ولا ؛ دول محتاجين اختبار deployment. مثال Testcontainers الرسمي.
#Database isolation و ليه EF InMemory مش بديلDatabase isolation and why EF InMemory is insufficient
لو test ناجح لوحده وفاشل مع باقي الـ suite، فتّش على داتا مشتركة. database لكل مجموعة مع reset بين الحالات حل عملي. Respawn بيقرأ العلاقات ويمسح الداتا بترتيب مناسب؛ شغله بعد migrations واحتفظ بجدول migration history. المثال fragment بعد فتح Npgsql connection اسمها connection على database اختبار فقط، مع package Respawn.
var reset = await Respawn.Respawner.CreateAsync(connection, new()
{
DbAdapter = Respawn.DbAdapter.Postgres,
SchemasToInclude = ["public"],
TablesToIgnore = [new Respawn.Graph.Table("__EFMigrationsHistory")]
}); // (1)
await reset.ResetAsync(connection); // (2)
// Seed only the data required by the next test.
- (1) خطة التنضيف بتتعمل بعد وجود الـ ، وبتستثني تاريخ migrations.
- (2) reset قبل كل حالة مع منع التنفيذ المتوازي على نفس الداتا.
rollback مفيد بس لو كل الشغل مشارك فعلاً في نفس transaction؛ request غالباً بيفتح connection تانية. InMemory مش relational: مش بيختبر translation ولا foreign keys ولا transactions الحقيقية. SQLite أحسن لبعض الحالات، لكن له dialect وسلوك مختلفين عن SQL Server و PostgreSQL. اختبر queries المهمة على نفس engine بتاع production. مقارنة EF الرسمية و Respawn.
#Contracts و Architecture testsContract and architecture tests
service ممكن يعدّي كل unit tests ويكسر consumer بتغيير اسم field. consumer-driven contract testing بيسجل الطلب والرد اللي consumer محتاجهم، و provider verification بيتأكد إن الـ provider الحقيقي ملتزم. Pact مثال؛ contract مش بديل لاختبار auth ولا رحلة business كاملة.
architecture tests بتمنع dependencies مخالفة للقرار المعماري. المثال كامل مع xUnit داخل test project بيعمل reference لـ domain assembly اسمها Store.Domain.
using System.Reflection;
using Xunit;
public sealed class DependencyTests
{
[Fact]
public void Domain_DoesNotReferenceEfCore()
{
var domain = Assembly.Load("Store.Domain"); // (1)
var references = domain.GetReferencedAssemblies();
Assert.DoesNotContain(references,
a => a.Name?.StartsWith("Microsoft.EntityFrameworkCore") == true); // (2)
}
}
- (1) بنفحص assembly محددة، مش كل dependencies بتاعة الاختبار.
- (2) الاختبار بيمسك references المباشرة لـ . مش بيكشف كل dependency غير مباشرة؛ tools زي ArchUnitNET تدي قواعد أوسع.
snapshot tests مفيدة لشكل ثابت، لكن لازم review للتغيير وتنضيف IDs والوقت المتغير. قبول snapshot جديد تلقائياً بيلغي قيمة الاختبار.
#TDD و BDD و Coverage و Mutation testingTDD, BDD, coverage and mutation testing
لما قاعدة الخصم مش واضحة، اكتب مثال متوقع الأول. دورة قصيرة: Red، اتأكد الاختبار فشل للسبب الصح؛ Green، أقل تنفيذ صحيح؛ Refactor، حسّن التصميم والاختبارات خضرا. بيبدأ بمحادثة وأمثلة مشتركة مع business، وممكن يصيغها Given و When و Then؛ مش مجرد tool أو syntax.
- اكتب حالة total عند حد الشحن المجاني.
- شغّلها قبل التنفيذ علشان تثبت إنها بتكشف السلوك الناقص.
- نفّذ، وبعدين أضف حالة أقل من الحد، وحسّن الكود.
line coverage بيقول إيه اتنفذ، و branch coverage بيوضح الفروع اللي اتاخدت؛ ولا واحد بيقيس قوة assertions. Stryker.NET بيغيّر الكود عمداً، زي >= إلى >؛ اختبار الحد لازم يفشل ويقتل الـ mutant.
#Flaky tests و Load و ConcurrencyFlaky tests, load and concurrency
الـ flaky test بيغير نتيجته من غير تغيير مقصود في الكود. الأسباب الشائعة وقت حقيقي، و random seed مش مسجل، و shared state، و network، وترتيب تنفيذ مفترض. استخدم clock متحكم فيه، وبيانات مستقلة، و bounded polling لشرط واضح بدل sleep عشوائي. العزل المؤقت محتاج owner وموعد إصلاح؛ retry لوحده بيخبي المشكلة.
k6 بيكتب load scenarios بـ JavaScript، و NBomber بيسمح بتعريفها بـ . حدد workload واقعي و arrival rate ومدة و warm-up، وراقب و error rate و و p99 مع و waits. اختبر البيئة المخصصة؛ load test مش unit test للـ race.
- لاختبار آخر قطعة: جهز stock = 1 في database حقيقية.
- استخدم مستقل لكل مشتري، ونسق البداية بإشارة أو barrier مناسب.
- نفذ المحاولتين، وتحقق إن نجاح واحد فقط، والمخزون مش سالب، والخاسر أخد نتيجة متوقعة.
- كرر بجدولة مختلفة، وأضف اختبارات retry و . التكرار يزوّد الثقة لكنه مش إثبات لكل interleaving.
أسئلة الانترفيو
مفيش نتايج
راجع فهمك
ليه الاختيار ده مناسب؟ إمتى ممكن ماينفعش؟ وإيه اللي هيتغير لو الحمل زاد أو ظهر فشل؟
21.1How do unit, integration and E2E tests differ?Junior
الـ unit بيفحص سلوك صغير من غير infrastructure، والـ integration بيفحص التوصيل الحقيقي، والـ بيجرب رحلة مستخدم كاملة. اختار المستوى اللي يمسك الخطر بأقل تكلفة تشخيص.
I distinguish them by the boundary they exercise. A unit test checks a small behavior without infrastructure, an integration test checks components working together, and an test exercises a complete user journey. I use units for calculation rules, integration tests for persistence and wiring, and selected E2E tests for checkout. I choose the cheapest level that can actually detect the failure rather than copying every scenario into all three layers.
21.2What makes a good unit test?Junior
اسم يشرح السلوك، و ، ونتيجة ثابتة، وسبب فشل واضح. FIRST بيفكرك بالسرعة والاستقلال والتكرار والتحقق التلقائي والكتابة في وقتها.
I want a test to explain one behavior, run quickly and produce a useful failure. I arrange explicit inputs, perform one meaningful action and assert its observable result. I keep it independent of other tests and control time and randomness. Multiple assertions are fine when they describe one outcome. I prefer behavior-based names and avoid private-method tests because refactoring should not break a test when the public behavior remains correct.
21.3When do you use Fact and Theory in xUnit?Junior
Fact لحالة ثابتة، و Theory لنفس القاعدة مع بيانات مختلفة. خلي أسماء الحالات والبيانات تساعدك تعرف الحد اللي اتكسر.
I use a Fact for a fixed scenario and a Theory when the same rule needs several input and expected-output pairs. For a shipping threshold, a Theory can cover values below, at and above the boundary. I keep the data small enough to understand and separate cases with different setup or meaning. Parameterization reduces duplication, but I do not turn unrelated behaviors into one large conditional test just to reuse a method.
21.4How do xUnit fixtures work?Mid
test class instance جديد لكل case، لكن IClassFixture بيتشارك داخل class، و ICollectionFixture بين classes في collection واحدة. مشاركة resource مش معناها مشاركة داتا من غير reset.
I use a class fixture to share expensive setup across one test class and a collection fixture when several classes need the same resource. xUnit still creates a new test-class instance for each case. In v3, async lifetime methods use ValueTask. I keep fixture lifetime separate from data : sharing a database container does not mean tests can share rows safely. I reset or partition data and avoid relying on test execution order.
21.5What are the different kinds of test doubles?Mid
dummy مش مستخدم، و stub رد جاهز، و fake تنفيذ مبسط، و mock تحقق من interaction، و spy تسجيل calls. الفرق في الدور مش اسم المكتبة.
I use dummy values only to fill unused parameters, stubs to return predefined answers, and fakes as simplified working implementations. A mock verifies an expected interaction, while a spy records calls for later inspection. NSubstitute and Moq can support several of these roles. I choose a double based on the behavior I need to control or observe, and I avoid verifying incidental internal calls that would make harmless refactoring expensive.
21.6What should you mock?Mid
تحكم في boundaries زي payment والوقت، واستخدم domain objects حقيقية. اختبر على engine حقيقي بدل mock لـ .
I usually replace nondeterministic or external boundaries, such as payment providers, email, time and remote . I keep domain objects real because their rules are what I want to exercise. For database queries, I prefer integration tests against the actual engine rather than mocking DbSet query behavior. If an application abstraction returns query results, I may stub that abstraction for a unit test, while separately testing its real database implementation.
21.7How do you test time-dependent behavior?Junior
احقن TimeProvider واستخدم FakeTimeProvider. اختبر قبل انتهاء المدة وعندها وبعدها من غير نوم حقيقي.
I inject TimeProvider instead of reading the machine clock directly. Tests use FakeTimeProvider with a fixed starting instant and advance it to the boundary being checked. That makes expiry tests fast and repeatable. I test before, at and after expiration, and distinguish elapsed duration from calendar time. For background timers, I also await an explicit completion signal because moving the fake clock does not guarantee every continuation has already finished.
21.8How would you integration-test an ASP.NET Core API?Mid
WebApplicationFactory للـ pipeline، و Testcontainers لنفس database engine، و migrations قبل الداتا، و fake للـ external payment فقط. تحقق من response ومن التخزين.
I host the with WebApplicationFactory, start a disposable database through Testcontainers, and configure the application to use it before the host starts. I apply migrations and seed only the scenario's data. Requests then exercise , routing, validation and persistence together. I replace external payment calls with a fake and inspect stored state through a fresh scope. I also run deployment checks separately because the default TestServer does not validate real or proxy configuration.
21.9Why avoid EF Core InMemory for database tests?Mid
مش relational ومش بيختبر translation أو أو constraints الحقيقية. SQLite ليه اختلافاته برضه؛ المطلوب engine مطابق للـ production.
I do not use InMemory to prove database correctness because it is not a relational engine. Passing tests cannot establish correct translation, foreign-key behavior or . SQLite is relational but still differs from SQL Server or PostgreSQL in dialect, types and comparison behavior. I test important queries and concurrency rules against the production database engine in disposable infrastructure, and use stubs above data access when a focused unit test needs predefined results.
21.10How do you isolate integration-test data?Senior
database مستقلة أو partition واضح، أو Respawn مع للـ reset. rollback مش كفاية لو الـ فتح connection خارج الاختبار.
I choose explicitly: a database per test group, unique data partitions, or a reset tool such as Respawn with serialized access to that database. I initialize reset metadata after migrations and preserve migration history. A rollback is useful only if all application work participates in that transaction; an request often uses another connection. I also account for background workers, because resetting rows while a worker still processes them can create intermittent failures.
21.11What is TDD, and where is it useful?Mid
Red فشل للسبب المقصود، و Green أقل تنفيذ صحيح، و Refactor تحسين والاختبارات خضرا. مناسب لقواعد business الواضحة بالأمثلة.
I use as a short feedback cycle: write a failing test, confirm the intended failure, add the minimum correct implementation, then refactor while tests remain green. It is especially useful for business rules with clear examples and boundary conditions. It encourages small interfaces and immediate feedback. I still need integration tests for infrastructure behavior, and I may first explore an unfamiliar before applying the cycle to the final implementation.
21.12Is 100 percent code coverage enough?Junior
لأ؛ تنفيذ السطر مش معناه assertion صح. راقب الفروع والحالات الحرجة، واستعمل mutation testing لتقييم قوة الاختبارات.
I treat coverage as a map of code that tests execute, not proof that the behavior is correct. A test can execute a line without asserting anything useful. Branch coverage adds information about decision paths, but it still misses weak expectations and missing requirements. I prioritize critical business rules, failure cases and boundaries, review uncovered areas, and use mutation testing selectively to see whether realistic changes would actually make tests fail.
21.13What does mutation testing tell you?Senior
Stryker بيغير operators أو قيم ويشوف الاختبارات هتفشل ولا لأ. survivor محتاج تحليل؛ ممكن يبقى مكافئ ومش نقص في tests.
I use mutation testing to challenge the assertions in a suite. A tool such as Stryker.NET makes small code changes and reruns tests; a failing test kills the mutant. Survivors can reveal missing boundary cases or weak assertions, but some mutations are behaviorally equivalent. I inspect survivors rather than enforcing a perfect score. Because the process is expensive, I start with critical calculations and run a broader campaign on an appropriate schedule.
21.14How do contract tests differ from E2E tests?Senior
contract بيثبت اتفاق consumer و provider عند boundary، والـ بيثبت رحلة متوصلة. لوحده مش بيغطي كل semantics.
I use contract tests to verify an agreement at a service boundary, including the requests a consumer sends and the responses it requires. Provider verification checks the actual provider against that agreement. This gives faster, more focused compatibility feedback than a full environment. It does not prove the entire business workflow, authorization configuration or network routing. I retain selected tests for those interactions and avoid treating a matching as complete semantic compatibility.
21.15How would you test two buyers competing for the last item?Senior
database حقيقية، و context مستقل لكل محاولة، وتنسيق بداية، و assert على : نجاح واحد ومخزون مش سالب. جرّب retry كمان.
I seed one item in the real database engine and run two purchase attempts with independent contexts and . I coordinate their execution so they can reach the contested operation together, then assert one successful reservation, an expected failure for the other and nonnegative persisted stock. I also test retry and behavior. Repeated runs help expose scheduling problems, but the underlying atomic update or concurrency constraint must enforce the in production.
21.16How do you investigate flaky tests?Mid
احفظ logs والـ seed وشغّل الحالة منفردة ومع parallelism. فتّش على clock و shared state و cleanup؛ ماتكتفيش بـ retry.
I preserve the failing logs, random seed and environment details, then compare isolated runs with full-suite and parallel runs. I look for shared data, uncontrolled clocks, incomplete async work, port conflicts and assumptions about ordering. I replace arbitrary sleeps with bounded waits for explicit conditions and give every resource a clear owner. If I quarantine a test temporarily, I assign an owner and deadline rather than allowing retries to turn an unreliable signal permanently green.
21.17How do you design a useful load test?Senior
ابدأ بهدف و workload واقعي. k6 و NBomber أدوات، لكن لازم arrival model ومقاييس /errors وبيئة معروفة.
I start with a capacity question and a representative workload, then choose an arrival model, request mix, duration and warm-up period. I can implement that with k6 or NBomber. I measure , errors and tail alongside application, database and infrastructure metrics. I also verify that the generator is not the bottleneck. A useful result identifies the saturation point and failure behavior; it does not merely report how many requests a synthetic endpoint completed.
21.18How do you choose an assertion library today?Mid
الـ built-in assertions كفاية. قارن readability والتكلفة والترخيص؛ FluentAssertions v8 تجاري للاستخدام التجاري، وفيه Shouldly و AwesomeAssertions كبدائل.
I start with the framework's built-in assertions and add a library when its diagnostics and readability justify the dependency. I review maintenance, compatibility and licensing before upgrading. FluentAssertions v8 requires a commercial license for commercial use, while Shouldly and AwesomeAssertions are alternatives worth evaluating. Whatever the syntax, I care more about precise expectations and helpful failure messages than fluent chaining, and I avoid asserting entire objects when only a small contractual outcome matters.
اختبر نفسك
إجابات الاختبار وعلامات إكمال المحاور بتتحفظ على المتصفح ده، ومش بتتنقل لأجهزة تانية.
Which test best validates PostgreSQL query translation?
Which xUnit abstraction shares setup across several test classes?
A line is covered but changing its result does not fail tests. What is likely missing?
How should an expiry test move time forward?
Which double returns predefined responses without a working implementation?
Why can transaction rollback fail to isolate an HTTP integration test?
What is the first step in a TDD cycle?
Two concurrent purchases are tested against one shared DbContext. What should change?
What does a passing consumer-driven contract primarily establish?
A test fails only in parallel runs. Best first investigation?