Boundary Value Analysis: 2-Value ve 3-Value BVA, Off-by-One, Tarih, Para ve Uzunluk Sınırları
Boundary value analysis, test değerini partition'ın ortasından değil sınırından ve komşusundan seçer; komşunun ne olduğunu tipin ve kuralın hassasiyeti belirler. Bookstore'da partition başına bir test yeşilken 500,00 TL ücretsiz kargo, UTC'ye kaymış Kasım kampanyası ve 23:59:59'da kapanan son saniye ancak sınır testleriyle yakalandı. 2-value ve 3-value BVA, FakeTimeProvider ile tarih sınırı, ISBN uzunluğu ve sepet boyutu.
Sürüm notu: Bu yazıdaki kodlar .NET 10, xUnit.net v3 4.0.3 ve Microsoft.Extensions.TimeProvider.Testing 11.0.0 ile derlenip denenmiştir.
Önce Tahmin Et
Sitedeki serilerin ortak örnek uygulaması Bookstore'da (bir online kitapçı) iki yeni kural var. İndirimli ara toplam 500 TL ve üstündeyse kargo ücretsiz. Kasım kampanyası 1 Kasım'dan 30 Kasım'a kadar sürüyor; back office ekranında kampanya gün olarak giriliyor ve günler İstanbul saatine göre. Emre'nin kodu:
namespace Bookstore.Shipping;
public static class FreeShippingPolicy
{
public const decimal Threshold = 500.00m;
public static bool Qualifies(decimal discountedSubtotal) => discountedSubtotal > Threshold;
}
namespace Bookstore.Catalog;
public sealed record Campaign(string Code, decimal Rate, DateTimeOffset StartsAt, DateTimeOffset EndsAt)
{
public static Campaign ForDays(string code, decimal rate, DateOnly firstDay, DateOnly lastDay) =>
new(code, rate,
new DateTimeOffset(firstDay.ToDateTime(TimeOnly.MinValue), TimeSpan.Zero),
new DateTimeOffset(lastDay.ToDateTime(new TimeOnly(23, 59, 59)), TimeSpan.Zero));
public bool IsActiveAt(DateTimeOffset instant) => instant >= StartsAt && instant <= EndsAt;
}
Ve testleri:
private static readonly Campaign NovemberSale =
Campaign.ForDays("NOVEMBER25", 0.25m, new DateOnly(2026, 11, 1), new DateOnly(2026, 11, 30));
[Theory]
[InlineData(250.00, false)]
[InlineData(750.00, true)]
public void Free_shipping_from_500_try(decimal subtotal, bool expected)
{
Assert.Equal(expected, FreeShippingPolicy.Qualifies(subtotal));
}
[Fact]
public void Campaign_is_active_in_november()
{
Assert.True(NovemberSale.IsActiveAt(new DateTimeOffset(2026, 11, 15, 12, 0, 0, TimeSpan.FromHours(3))));
Assert.False(NovemberSale.IsActiveAt(new DateTimeOffset(2026, 12, 10, 12, 0, 0, TimeSpan.FromHours(3))));
}
Testler yeşil. Önceki yazının diliyle söylersek her partition'dan bir temsilci var: kargoda "500'ün altı" ve "500 ve üstü", kampanyada "kampanya içi" ve "kampanya sonrası". Equivalence partitioning açısından eksik yok. Bu iki class'ta kaç hata var?
Cevap: Hatalar Sınırda
Üç tane, üçü de sınırda. FreeShippingPolicy > kullanıyor; 500,00 TL'lik sepet ücretsiz kargo almıyor. Campaign.ForDays günleri UTC (Coordinated Universal Time; dünya genelinde referans alınan saat) gününe çeviriyor, yani kampanya İstanbul saatiyle 1 Kasım 03:00'te başlayıp 1 Aralık 02:59:59'da bitiyor. Bitiş anını da 23:59:59 olarak, saniyenin başında kapatıyor; son saniyenin içindeki her an kampanya dışında kalıyor.
Bu hataların ilki literatürdeki adıyla off-by-one hatası (sınırın bir adım kaymış olması): >= yerine >, < yerine <=, 13 yerine 12 hane. Kampanyadaki iki hata da aynı ailenin üyeleri; biri sınırı üç saat, diğeri bir saniye kaydırıyor. Syllabus'ın sınır değer testleri için saydığı tipik hatalar da bunlar: sınırın olması gereken yerin üstüne ya da altına konması, ya da hiç konmaması.
Üç hatanın ortak yanı, partition'ların ortasındaki hiçbir değerin onları göstermemesi. 250 ve 750 TL, 15 Kasım öğlen ve 10 Aralık öğlen kodda doğru yoldan geçiyor. Hata, iki partition'ın birleştiği yerde, kodun sınırı yanlış yere koymasında. Equivalence partitioning her partition'dan bir değer ister ama hangisi olduğunu söylemez. Boundary value analysis tam bu boşluğu doldurur: değeri sınırdan seç.
Sınır Değeri ve Komşusu: 2-value ve 3-value BVA
Boundary value analysis, kısaca BVA (sınır değer analizi), partition'ların kenarlarını test eder. Bir partition'ın en küçük ve en büyük değeri onun sınır değerleridir. Bunun bir ön şartı var: partition sıralı olmalı. Sayılar, tarihler, uzunluklar sıralıdır; iki değer aynı partition'daysa aradaki her değer de o partition'dadır. Müşteri tipi ya da ödeme yöntemi gibi enum'lar sıralı değildir, onlarda sınır diye bir şey yoktur ve BVA uygulanmaz.
ISTQB (International Software Testing Qualifications Board; yazılım test sertifikalarını tanımlayan uluslararası kurul) CTFL (Certified Tester Foundation Level; temel seviye test sertifikası) v4.0.1 syllabus'ı iki sürüm tanımlar. 2-value BVA'da her sınır değeri için iki coverage item vardır: sınır değerinin kendisi ve komşu partition'daki en yakın değer. Ücretsiz kargo için bunlar 499,99 ve 500,00. 3-value BVA'da her sınır değeri için üç coverage item vardır: sınır değeri ve iki yanındaki komşusu. Kargo için kümeye 499,98 ve 500,01 eklenir.
Syllabus'ın 3-value için verdiği gerekçe şu: x <= 10 olması gereken bir koşul yanlışlıkla x == 10 yazılırsa, 2-value'nun iki değeri (10 ve 11) hatayı göstermez, 3-value'nun eklediği 9 gösterir. Küçük Bir Deneme'deki son alıştırma bu durumu Bookstore'un minimum adet kuralında yeniden üretiyor.
"En yakın değer" tipin ve iş kuralının hassasiyetine bağlıdır ve BVA'nın en çok atlanan kısmı budur. Tutar kuruş hassasiyetindeyse adım 0,01 TL'dir. DateTimeOffset'in adımı bir tick, yani 100 nanosaniyedir. Değer veritabanına datetime2(0) gibi saniye hassasiyetli bir kolonla yazılıyorsa, iş kuralı açısından adım bir saniyeye çıkar. Komşuyu yanlış hassasiyetle seçmek, aslında aynı partition'da kalan bir değeri sınırın öbür yanı sanmak demektir.

Para Sınırı: 499,99 ve 500,00
Kargo kuralının partition'ları "500'ün altı" ve "500 ve üstü", alt uçta da 0,00. Test verisi doğrudan bu sayı doğrusundan geliyor:
namespace Bookstore.Shipping.Tests;
public sealed class FreeShippingPolicyTests
{
// 3-value BVA: sınır değerleri 499.99 ve 500.00, komşuları 499.98 ve 500.01 (en küçük adım: 1 kuruş)
public static TheoryData<decimal, bool> ThresholdBoundaries => new()
{
{ 0.00m, false },
{ 499.98m, false },
{ 499.99m, false },
{ 500.00m, true },
{ 500.01m, true },
};
[Theory]
[MemberData(nameof(ThresholdBoundaries))]
public void Free_shipping_starts_at_exactly_500_try(decimal discountedSubtotal, bool expected)
{
Assert.Equal(expected, FreeShippingPolicy.Qualifies(discountedSubtotal));
}
}
InlineData yerine TheoryData<decimal, bool> kullanmamızın sebebi Unit Test serisinin "xUnit v3'te Veri Odaklı Testler" yazısında anlatılıyor: attribute argümanı decimal olamaz ve kuruş seviyesindeki değerlerde double üzerinden dönüşüm riskine girmek istemiyoruz.
Bir ayrıntı daha: kural "indirimli ara toplam" diyor. Ara toplam bu noktaya gelmeden önce kuruşa yuvarlanmış olmalı; yuvarlanmamış 499,995 gibi bir değer politika class'ına ulaşırsa 499,99 ile 500,00 arasında, kuralın hiç tanımlamadığı bir bölge oluşur. Bu yüzden sınırın nerede olduğunu bilmek için yuvarlamanın nerede yapıldığını bilmek gerekiyor. Çözüm Desenleri serisinin "Para ve Yuvarlama" yazısı yuvarlamayı tek bir yerde, Money value object'inde toplamayı anlatıyor; o durumda bu politika her zaman iki ondalıklı bir tutar alır.
Tarih Sınırı: 23:59:59 mu, Ertesi Gün 00:00 mı?
Kampanyanın zaman ekseninde üç partition var: başlamadan önce, kampanya süresince, bittikten sonra. Sınırlar iki an: İstanbul saatiyle 1 Kasım 00:00 ve 1 Aralık 00:00. Kampanyayı "1 Kasım 00:00 dahil, 1 Aralık 00:00 hariç" diye, yarı açık bir aralık olarak tanımlamak işi kolaylaştırır: "son gün"ün son anını bulmak zorunda kalmazsın, çünkü bitiş anı bir sonraki günün başıdır ve aralığa dahil değildir. Test verisi:
using Microsoft.Extensions.Time.Testing;
namespace Bookstore.Catalog.Tests;
public sealed class CampaignTests
{
// Kampanya 1-30 Kasım, İstanbul saatiyle; aralık [1 Kasım 00:00, 1 Aralık 00:00)
private static readonly TimeSpan Istanbul = TimeSpan.FromHours(3);
private static readonly DateTimeOffset Start = new(2026, 11, 1, 0, 0, 0, Istanbul);
private static readonly DateTimeOffset End = new(2026, 12, 1, 0, 0, 0, Istanbul);
private static readonly TimeSpan Tick = TimeSpan.FromTicks(1);
private static readonly Campaign NovemberSale =
Campaign.ForDays("NOVEMBER25", 0.25m, new DateOnly(2026, 11, 1), new DateOnly(2026, 11, 30));
// Sınır değerleri ve komşuları (en küçük adım: 1 tick = 100 ns)
public static TheoryData<DateTimeOffset, bool> Boundaries => new()
{
{ Start - 2 * Tick, false },
{ Start - Tick, false },
{ Start, true },
{ Start + Tick, true },
{ End - 2 * Tick, true },
{ End - Tick, true },
{ End, false },
{ End + Tick, false },
};
[Theory]
[MemberData(nameof(Boundaries))]
public void Campaign_runs_from_first_day_to_end_of_last_day_in_istanbul(DateTimeOffset instant, bool active)
{
Assert.Equal(active, NovemberSale.IsActiveAt(instant));
}
[Fact]
public void Calendar_drops_the_campaign_at_midnight_istanbul_time()
{
FakeTimeProvider time = new(End - Tick);
CampaignCalendar calendar = new(time);
Assert.Single(calendar.ActiveCampaigns([NovemberSale]));
time.Advance(Tick);
Assert.Empty(calendar.ActiveCampaigns([NovemberSale]));
}
}
Testte İstanbul'u TimeZoneInfo ile değil, sabit +03:00 ile yazdık. Türkiye 2016'dan beri yıl boyu UTC+3 kullanıyor; testin beklenen değerini kodun kullandığı time zone veritabanından bağımsız tutmak, ikisinin aynı yanlışı yapmasını önlüyor. Son test, kampanyaları listeleyen CampaignCalendar'ı FakeTimeProvider ile tam sınıra götürüp bir tick ilerletiyor. TimeProvider ve FakeTimeProvider'ın kullanımını Unit Test serisinin "Unit Test'te Zor Durumlar" yazısında anlatmıştık; burada önemli olan, saati dışarıdan almayan bir kodda bu testin yazılamaması. DateTimeOffset.UtcNow okuyan bir class'ı 30 Kasım 23:59:59,9999999'a götürmenin yolu yok.
Eski koda karşı, kargo testleriyle birlikte (stack trace'ler kısaltıldı):
failed Bookstore.Shipping.Tests.FreeShippingPolicyTests.Free_shipping_starts_at_exactly_500_try(discountedSubtotal: 500.00, expected: True) (0ms)
Assert.Equal() Failure: Values differ
Expected: True
Actual: False
failed Bookstore.Catalog.Tests.CampaignTests.Campaign_runs_from_first_day_to_end_of_last_day_in_istanbul(instant: 2026-11-01T00:00:00.0000001+03:00, active: True) (1ms)
Assert.Equal() Failure: Values differ
Expected: True
Actual: False
failed Bookstore.Catalog.Tests.CampaignTests.Campaign_runs_from_first_day_to_end_of_last_day_in_istanbul(instant: 2026-11-01T00:00:00.0000000+03:00, active: True) (0ms)
Assert.Equal() Failure: Values differ
Expected: True
Actual: False
failed Bookstore.Catalog.Tests.CampaignTests.Campaign_runs_from_first_day_to_end_of_last_day_in_istanbul(instant: 2026-12-01T00:00:00.0000000+03:00, active: False) (0ms)
Assert.Equal() Failure: Values differ
Expected: False
Actual: True
failed Bookstore.Catalog.Tests.CampaignTests.Campaign_runs_from_first_day_to_end_of_last_day_in_istanbul(instant: 2026-12-01T00:00:00.0000001+03:00, active: False) (0ms)
Assert.Equal() Failure: Values differ
Expected: False
Actual: True
failed Bookstore.Catalog.Tests.CampaignTests.Calendar_drops_the_campaign_at_midnight_istanbul_time (4ms)
Assert.Empty() Failure: Collection was not empty
Collection: [Campaign { Code = NOVEMBER25, Rate = 0.25, StartsAt = 11/1/2026 12:00:00 AM +00:00, EndsAt = 11/30/2026 11:59:59 PM +00:00 }]
Test run summary: Failed!
total: 42
failed: 6
succeeded: 36
skipped: 0
Kargo hatasını 500,00 yakaladı; 2-value BVA bu hata için yeterli. Kampanyada başlangıç ve bitişin hemen etrafındaki dört değer kırmızı. Son test, Campaign'in kaydını da bastığı için hatanın kaynağını gösteriyor: StartsAt ve EndsAt +00:00 offset'li. Kampanya üç saat kaymış.
İlk düzeltme, günleri İstanbul saatine çevirmek. Emre bitişi yine 23:59:59 bırakıyor:
private static readonly TimeZoneInfo Istanbul = TimeZoneInfo.FindSystemTimeZoneById("Europe/Istanbul");
public static Campaign ForDays(string code, decimal rate, DateOnly firstDay, DateOnly lastDay) =>
new(code, rate, AtIstanbul(firstDay, TimeOnly.MinValue), AtIstanbul(lastDay, new TimeOnly(23, 59, 59)));
public bool IsActiveAt(DateTimeOffset instant) => instant >= StartsAt && instant <= EndsAt;
private static DateTimeOffset AtIstanbul(DateOnly day, TimeOnly time)
{
DateTime local = day.ToDateTime(time);
return new DateTimeOffset(local, Istanbul.GetUtcOffset(local));
}
failed Bookstore.Catalog.Tests.CampaignTests.Campaign_runs_from_first_day_to_end_of_last_day_in_istanbul(instant: 2026-11-30T23:59:59.9999999+03:00, active: True) (0ms)
Assert.Equal() Failure: Values differ
Expected: True
Actual: False
failed Bookstore.Catalog.Tests.CampaignTests.Campaign_runs_from_first_day_to_end_of_last_day_in_istanbul(instant: 2026-11-30T23:59:59.9999998+03:00, active: True) (0ms)
Assert.Equal() Failure: Values differ
Expected: True
Actual: False
failed Bookstore.Catalog.Tests.CampaignTests.Calendar_drops_the_campaign_at_midnight_istanbul_time (1ms)
Assert.Single() Failure: The collection was empty
Test run summary: Failed!
total: 16
failed: 3
succeeded: 13
skipped: 0
Time zone düzeldi, şimdi ikinci hata görünür oldu. 30 Kasım 23:59:59,5'te sepete kitap ekleyen müşteri kampanya fiyatını görmüyor. Hatayı yakalayan değerler, aktif partition'ın en büyük değeri olan End - Tick ve onun komşusu End - 2 * Tick. Burada belirleyici olan 2-value ya da 3-value seçimi değil, hassasiyet. "Son an 23:59:59" diye düşünüp sınır değerini saniye hassasiyetinde seçen biri, 23:59:59,0'ı ve 1 Aralık 00:00'ı test eder; ikisi de doğru sonucu verir ve hata görünmez. Kuralın gerçek hassasiyeti tick olduğu için sınır değeri de tick hassasiyetinde seçilmeli.
Kalıcı düzeltme bitişi bir sonraki günün başına almak ve aralığı yarı açık yapmak:
public static Campaign ForDays(string code, decimal rate, DateOnly firstDay, DateOnly lastDay) =>
new(code, rate, StartOfDayInIstanbul(firstDay), StartOfDayInIstanbul(lastDay.AddDays(1)));
// [StartsAt, EndsAt): bitiş anı kampanyaya dahil değil
public bool IsActiveAt(DateTimeOffset instant) => instant >= StartsAt && instant < EndsAt;
private static DateTimeOffset StartOfDayInIstanbul(DateOnly day)
{
DateTime local = day.ToDateTime(TimeOnly.MinValue);
return new DateTimeOffset(local, Istanbul.GetUtcOffset(local));
}
Kargo politikasında da > yerine >=:
Test run summary: Passed!
total: 42
failed: 0
succeeded: 42
skipped: 0
duration: 358ms
"Europe/Istanbul" IANA (Internet Assigned Numbers Authority; time zone veritabanını yayımlayan kuruluş) kimliği. Windows'ta .NET 6'dan beri FindSystemTimeZoneById ICU (International Components for Unicode; işletim sisteminin globalization library'si) mevcutsa IANA kimliklerini de kabul ediyor; ICU'su olmayan eski bir Windows Server'da Windows kimliğini ("Turkey Standard Time") kullanmak gerekir. Saat ve time zone konusunun bütünü Çözüm Desenleri serisinin "Zaman ve Time Zone" yazısında.
Uzunluk ve Collection Boyutu
Sıralı olan her şeyin sınırı vardır; uzunluk ve eleman sayısı da sıralıdır. ISBN (International Standard Book Number; kitapların uluslararası kimlik numarası) doğrulamasında hane sayısının partition'ları 0–12 (geçersiz), 13 (geçerli) ve 14 ve üstü (geçersiz). Geçerli partition tek bir değerden oluşuyor, yani 13 hem en küçük hem en büyük değeri. 2-value BVA 12, 13 ve 14'ü verir; 3-value 11 ve 15'i ekler:
namespace Bookstore.Catalog.Tests;
public sealed class Isbn13Tests
{
// Hane sayısı: 0-12 geçersiz, 13 geçerli, 14+ geçersiz; 3-value BVA ile 11..15
[Theory]
[InlineData("97804411727", false)]
[InlineData("978044117271", false)]
[InlineData("9780441172719", true)]
[InlineData("97804411727190", false)]
[InlineData("978044117271900", false)]
[InlineData("978-0-441-17271-9", true)]
[InlineData("", false)]
public void Isbn_must_have_exactly_13_digits(string value, bool valid)
{
Assert.Equal(valid, Isbn13.IsValid(value));
}
}
Tireli satır başka bir sınırı hatırlatıyor: 13 hane tirelerle 17 karakter. Hane sayısının sınırı 13, ham girdinin uzunluk sınırı 17. Veritabanında ISBN kolonu nvarchar(13) ise ve normalize etmeden yazan bir kod yolu varsa, sınır uygulamada değil kolonda ortaya çıkar. Sınırları yalnızca kuralın cümlesinde değil, değerin geçtiği her katmanda aramak gerekir.
Collection boyutu da aynı mantıkla test edilir. Sepette en fazla 50 farklı kitap satırı olabiliyor. Partition'lar 0 satır (boş sepet), 1–50 ve 51 ve üstü; test, sepeti sınırın bir eksiğine kadar doldurup bir satır daha ekliyor:
namespace Bookstore.Ordering.Tests;
public sealed class CartTests
{
// Satır sayısı 1-50 geçerli: boş sepet, 49 -> 50 ve 50 -> 51
[Theory]
[InlineData(0, true)]
[InlineData(49, true)]
[InlineData(50, false)]
public void Cart_holds_at_most_50_lines(int existingLines, bool accepted)
{
Cart cart = new();
for (int i = 0; i < existingLines; i++)
{
cart.TryAdd(new OrderLine($"isbn-{i}", 100m, 1));
}
bool added = cart.TryAdd(new OrderLine("9780441172719", 250m, 1));
Assert.Equal(accepted, added);
Assert.Equal(accepted ? existingLines + 1 : existingLines, cart.Lines.Count);
}
}
İkinci assertion önemli: 51. satır reddedildiğinde sepetin değişmediğini de doğruluyor. Sınırda "reddetti" demek yetmez; reddettikten sonra durumun bozulmadığını da görmek gerekir.
Üretimde Dikkat
Sınırı tek bir yerde tanımla. FreeShippingPolicy.Threshold gibi bir sabit, kampanya ekranındaki "ücretsiz kargoya 12,50 TL kaldı" mesajında, e-postadaki metinde ve raporlardaki filtrede aynı değer olmalı. Aynı sınır üç yerde üç farklı karşılaştırmayla yazıldığında, biri > biri >= olur ve müşteri ekranla faturanın farklı şey söylediğini görür.
Zamanı UTC sakla, kuralı yerel günle konuş. Kampanyayı back office "1–30 Kasım" diye giriyor; bu günlerin hangi time zone'da olduğu bir iş kararıdır ve kodda tek bir yerde, ForDays gibi bir factory method'unda anlam kazanmalı. Kampanya yurt dışından da sipariş alıyorsa "1 Aralık 00:00 kimin saatiyle?" sorusunu Selin'e sor; cevap testteki +03:00'ı belirler.
Veritabanının hassasiyetini kontrol et. Bir anı tick hassasiyetinde hesaplayıp saniye hassasiyetli bir kolona yazarsan, kayıttan okunan bitiş anı hesaplanandan farklı olabilir. SQL Server'ın datetime2 tipinin varsayılan hassasiyeti 7 basamak, yani tick; datetime tipi ise yaklaşık 3 milisaniyeye yuvarlar. Sınır testini bir de veritabanından okunan değerle çalıştırmak, bu farkı integration test seviyesinde yakalar.
Production'daki gerçek sınır olaylarını izle. Kampanya bitişinden sonraki ilk dakikalarda kampanya fiyatıyla oluşan sipariş sayısı, sınır hatasının en doğrudan ölçüsüdür. Bu sayının sıfır olmadığı bir gece, testlerinin bir komşuyu atladığını gösterir.
Sık Düşülen Tuzaklar
Sınırı yalnızca geçerli tarafta test etmek. 500,00'ı test edip 499,99'u atlamak, sınırın doğru yerde olduğunu değil, yalnızca 500,00'ın ücretsiz olduğunu gösterir. Kod >= 499.50m olsa da test geçer. Sınırın iki yanı birlikte test edilir.
Komşuyu yanlış hassasiyetle seçmek. Saniye hassasiyetiyle düşünüp 23:59:59'u "son an" saymak, bu yazıdaki ikinci hatanın kaynağı. Tutarlarda 0,01, tarihlerde tipin ve kolonun hassasiyeti, uzunlukta bir karakter, collection'da bir eleman.
Tarih sınırını gerçek saatle test etmek. DateTimeOffset.UtcNow'a bağlı bir kod, ancak test tam o saniyede çalışırsa sınırda test edilebilir. TimeProvider ile saati dışarıdan almak, sınır testini mümkün kılan şeydir.
Time zone'u testte de koddaki yöntemle hesaplamak. Beklenen değeri TimeZoneInfo.FindSystemTimeZoneById("Europe/Istanbul") ile üreten bir test, kodla aynı varsayımı paylaşır. Beklenen anı sabit bir offset ya da UTC olarak açıkça yaz.
Sıralı olmayan girdiye BVA uygulamaya çalışmak. Ödeme yönteminin "sınırı" yoktur. BVA'yı yalnızca sıralı partition'larda kullan; enum'lar ve kategoriler için equivalence partitioning yeterli.
Küçük Bir Deneme
★☆☆ FreeShippingPolicy.Qualifies'ı discountedSubtotal >= 499.99m olarak boz. Bu yazıdaki beş satırdan hangisi kırmızıya döner? Yalnızca 2-value BVA'nın değerleriyle de yakalanır mıydı?
★★☆ Kampanyaya "son gün 18:00'de biter" kuralını ekle: Kasım kampanyası 30 Kasım 18:00'de, İstanbul saatiyle bitsin. ForDays'e nasıl bir parametre eklersin? Önce sınır değerlerini ve komşularını yaz, sonra kodu değiştir.
★★★ Kurumsal minimum 20 adet kuralı için 3-value BVA ile test case'leri çıkar (18, 19, 20, 21) ve InstitutionalPricing.Price'a karşı çalıştır. Sonra minimum kontrolünü totalQuantity == MinimumQuantity - 1 yapan, yani yalnızca 19 adedi reddeden bozuk bir sürüm yaz. 2-value BVA'nın değerleri (19 ve 20) bu hatayı yakalar mı? 3-value'nun eklediği hangi değer yakalar?
Equivalence partitioning ve boundary value analysis tek tek girdilere bakıyordu. Bir sonraki yazıda kuralın birden fazla koşulun kombinasyonuna bağlı olduğu yere geçiyoruz: decision table testing. Kargo ücretinin üyelik, sepet tutarı, bölge ve kupon kombinasyonlarından tabloyu kurup sadeleştirecek, tablonun requirement'taki çelişkiyi nasıl gösterdiğini ve testi implementasyondaki kural tablosundan kopyalamanın neden işe yaramadığını göreceğiz.