Birim test ve üst seviye test (entegrasyon/sistem) örneklerini ayırt eder; hangi örneğin hangi test seviyesine hizmet ettiğini açıklar.
Verilen sözde kod üzerinden temel kontrol yapılarıyla (sequence/selection/loop/case) program akışını okuyup karar noktalarını belirler.
Triangle / NextDate / Commission örneklerinde girdi uzayı, sınır değerler ve geçersiz kombinasyonlar kavramlarını kullanarak test gereksinimlerini çıkarır.
“Basit” ve “geliştirilmiş” sürümler arasındaki farkları input doğrulama + hata davranışı + test edilebilirlik açısından analiz eder.
SATM, GUI döviz çevirici, silecek kontrolörü ve garaj kapısı gibi örnekleri durum/olay tabanlı davranış perspektifinden yorumlayarak, uygun modelleme yaklaşımını (FSM/Statechart/UML/decision table) seçer.
Ortak Senaryo Setleri
Ders boyunca farklı test yöntemlerini somutlaştırmak için tekrar tekrar kullanılacak örnekler seçilmiştir.
İki ana kategoriye ayrılır:
Birim test (unit) düzeyi → 3 Örnek
Daha üst test seviyeleri → 5 Örnek
Birim Test (Unit) Düzeyi Örnekler
Üçgen problemi
NextDate
Commission problem
Daha Üst Test Seviyeleri Örnekler
Basitleştirilmiş ATM sistemi (SATM)
Döviz çevirici
GUI tabanlı olay güdümlü bir uygulama
Saturn araç silecek kontrol sistemi
Garaj kapısı kontrolörü
Genelleştirilmiş Sözde Kod (Pseudocode)
Sözde kod, programı dilden bağımsız ifade etme yoludur.
Amaç: Gereksiz ayrıntıyı gizleyip, test için önemli olan yapıyı görünür kılmak.
Bu sözde kod yaklaşımı iki seviyeyi kapsar:
Birim (procedure/function ya da sınıf/metot)
Program bileşenleri
Köşeli parantez içindeki ifadeler (<...>) ilgili yerde kullanılabilecek yer tutucuları gösterir.
Gerektiğinde karmaşık koşullar yerine daha anlaşılır doğal dil ifadelerine izin verilir.
Genelleştirilmiş Sözde Kod Yapıları
Dil Elemanı
Genelleştirilmiş Sözde Kod Yapısı
Comment
<text>
Data structure declaration
Type <type name> <list of field descriptions> End <type name>
Data declaration
Dim <variable> As <type>
Assignment statement
<variable> = <expression>
Input
Input (<variable list>)
Output
Output (<variable list>)
Condition
<expression> <relational operator> <expression>
Compound condition
<Condition> <logical connective> <Condition>
Sequence
statements in sequential order
Simple selection
If <condition> Then <then clause> EndIf
Selection
If <condition> Then <then clause> Else <else clause> EndIf
Multiple selection
Case <variable> Of Case 1: <predicate> <Case clause> ... Case n: <predicate> <Case clause> EndCase
Counter-controlled repetition
For <counter> = <start> To <end> <loop body> EndFor
Pretest repetition
While <condition> <loop body> EndWhile
Posttest repetition
Do <loop body> Until <condition>
Procedure definition
<procedure name> (Input: <list of variables>; Output: <list of variables>) <body> End <procedure name>
Interunit communication
Call <procedure name> (<list of variables>; <list of variables>)
Class/Object definition
<name> (<attribute list>; <method list>, <body>) End <name>
Interunit communication
msg <destination object name>.<method name> (<list of variables>)
Object creation
Instantiate <class name>.<object name> (list of attribute values)
Object destruction
Delete <class name>.<object name>
Program
Program <program name> <unit list> End <program name>
Üçgen Problemi (Triangle Problem)
Üçgen problemi, yazılım testi literatüründe en yaygın kullanılan örneklerden biridir.
Bu ders kapsamında üçgen problemi:
test tekniklerini aynı problem üzerinde karşılaştırmak,
“girdi uzayı” ve “sınır durum” düşüncesini göstermek için kullanılacaktır.
Problem Tanımı (Basit Sürüm)
Program üç tamsayı alır: a, b, c
Bu değerler bir üçgenin kenar uzunlukları olarak yorumlanır
Çıktı, üçgenin türüdür:
Equilateral (Eşkenar)
Isosceles (İkizkenar)
Scalene (Çeşitkenar)
NotATriangle (Üçgen değil)
Bazı varyantlarda Right triangle (dik üçgen) ayrı bir tür olarak eklenebilir
Problem Tanımı (Geliştirilmiş Sürüm)
Program üç tamsayı alır: a, b, c. Şu koşullar sağlanmalıdır:
Aralık koşulları
c1. 1 ≤ a ≤ 200
c2. 1 ≤ b ≤ 200
c3. 1 ≤ c ≤ 200
Üçgen eşitsizliği koşulları
c4. a < b + c
c5. b < a + c
c6. c < a + b
Çıktı Kuralları
Eğer giriş değerleri c1, c2 veya c3 koşullarından birini sağlamazsa:
Program bir hata mesajı üretir (örn. “Değer izin verilen aralıkta değil.”)
Eğer c4, c5, c6 sağlanıyorsa, çıktı şu dört durumdan biri olur:
a = b = c ise → Equilateral
Tam olarak bir çift eşitse (örn. a=b≠c) → Isosceles
Hiçbir çift eşit değilse → Scalene
c4, c5, c6 koşullarından biri sağlanmazsa → NotATriangle
Tartışma
Bu örneğin yıllardır kullanılmasının bir nedeni mantığının net, ama aynı zamanda karmaşık olmasıdır.
Ayrıca, gerçek hayatta sık görülen bir probleme işaret eder:
eksik/yarım tanımlar, müşteri–geliştirici–testçi arasında iletişimi bozar.
Örnek bir “varsayım”:
Üçgen eşitsizliğini geliştiricinin zaten bildiği kabul edilir
(iki kenarın toplamı, üçüncü kenardan büyük olmalı)
Üst sınır olan 200 değeri ise hem keyfi hemde kullanışlı bir aralık sunar.
Geleneksel Uygulama
Bu klasik örneğin “geleneksel” uygulaması FORTRAN benzeri bir stile sahiptir.
Akış diyagramları:
Geleneksel uygulama
Geliştirilmiş uygulama (2 versiyon)
Akış Diyagramı: Geleneksel Uygulama
Match Değişkeni: Ne İşe Yarar?
match değişkeni, kenarlar arasındaki eşitlik durumunu kaydetmek için kullanılır.
FORTRAN tarzındaki klasik ayrıntı:
Üçgen eşitsizliği kontrollerinin hepsi her zaman yapılmaz.
Örn. iki kenar eşitse (a=c gibi) sadece gerekli karşılaştırmalar seçilir.
Bu yaklaşım bazı karşılaştırmaları azaltır ama okunabilirliği düşürür.
Verimlilik mi Netlik mi?
Bu sürümde verimlilik, anlaşılırlık (ve test edilebilirlik) pahasına elde edilir.
Bu örnek ileride şu konuyu tartışmak için özellikle faydalıdır:
Çalıştırılamayan program yürütme yolları (infeasible paths)
Yol Çeşitliliği (Path Variety)
Bu akışta bazı çıktılara birden fazla yoldan gidilir:
NotATriangle kutusuna ulaşmak için birden çok yol vardır.
Isosceles kutusuna ulaşmak için de birden çok yol vardır.
Bu durum, test tasarımında “hangi yolları hedefliyoruz?” sorusunu doğurur.
Sözde Kod (Geleneksel)
Program triangle1Dim a, b, c, match AsINTEGEROutput("Enter 3 integers which are sides of a triangle")Input(a, b, c)Output("Side A is", a)Output("Side B is", b)Output("Side C is", c)match = 0If a = b '(1)Then match = match + 1 '(2)EndIfIf a = c '(3)Then match = match + 2 '(4)EndIfIf b = c '(5)Then match = match + 3 '(6)EndIfIf match = 0 '(7)ThenIf (a + b) <= c '(8)Then Output("NotATriangle") '(12.1) ElseIf (b + c) <= a '(9)Then Output("NotATriangle") '(12.2) ElseIf (a + c) <= b '(10)Then Output("NotATriangle") '(12.3)Else Output("Scalene") '(11) EndIfElseIf match = 1 '(13)ThenIf (a + c) <= b '(14)Then Output("NotATriangle") '(12.4)Else Output("Isosceles") '(15.1) EndIfElseIf match = 2 '(16)ThenIf (a + c) <= bThen Output("NotATriangle") '(12.5)Else Output("Isosceles") '(15.2) EndIfElseIf match = 3 '(18)ThenIf (b + c) <= a '(19)Then Output("NotATriangle") '(12.6)Else Output("Isosceles") '(15.3) EndIfElse Output("Equilateral") '(20)EndIfEnd Triangle1
Aynı problem, daha okunabilir şekilde yapılandırılmış programlama ile de yazılabilir.
Amaç:
koşulları daha net görmek
test case üretimini kolaylaştırmak
Bu bölümde iki sürüm var:
triangle2: daha basit spesifikasyonun yapılandırılmış hali
triangle3: aralık kontrollerini de içeren daha kapsamlı sürüm
triangle2: Yapılandırılmış sürümün fikri
3 adım:
Girdiyi al
Üçgen mi kontrol et (IsATriangle)
Üçgense türünü belirle
Bu yapı, “önce geçerlilik, sonra sınıflandırma” ayrımını netleştirir.
Sözde Kod (triangle2)
Program triangle2Dim a,b,c AsIntegerDim IsATriangle AsBoolean'Step 1: Get InputOutput("Enter 3 integers which are sides of a triangle")Input(a,b,c)Output("Side A is",a)Output("Side B is",b)Output("Side C is",c)'Step 2: Is A Triangle?If (a < b + c) AND (b < a + c) AND (c < a + b)Then IsATriangle = TrueElse IsATriangle = FalseEndIf'Step 3: Determine Triangle TypeIf IsATriangleThenIf (a = b) AND (b = c)Then Output ("Equilateral")ElseIf (a # b) AND (a # c) AND (b # c)Then Output ("Scalene")Else Output ("Isosceles") EndIf EndIfElse Output("Not a Triangle")EndIfEnd triangle2
triangle3: Aralık kontrolleri eklenmiş sürüm
triangle3, ayrıca şu kontrolleri de içerir:
1 ≤ a ≤ 300
1 ≤ b ≤ 300
1 ≤ c ≤ 300
Geçersiz girişlerde mesaj üretir ve geçerli giriş gelene kadar tekrar ister.
Sözde Kod (triangle3)
Program triangle3Dim a, b, c AsIntegerDim c1, c2, c3, IsATriangle AsBoolean'Step 1: Get InputDo Output("Enter 3 integers which are sides of a triangle") Input(a, b, c) c1 = (1 <= a) AND (a <= 300) c2 = (1 <= b) AND (b <= 300) c3 = (1 <= c) AND (c <= 300)If NOT(c1)Then Output("Value of a is not in the range of permitted values") EndIfIf NOT(c2)Then Output("Value of b is not in the range of permitted values") EndIfIf NOT(c3) ThenOutput("Value of c is not in the range of permitted values") EndIfUntil c1 AND c2 AND c3Output("Side A is",a)Output("Side B is",b)Output("Side C is",c)'Step 2: Is A Triangle?If (a < b + c) AND (b < a + c) AND (c < a + b)Then IsATriangle = TrueElse IsATriangle = FalseEndIf'Step 3: Determine Triangle TypeIf IsATriangleThenIf (a = b) AND (b = c)Then Output ("Equilateral")ElseIf (a # b) AND (a # c) AND (b # c)Then Output ("Scalene")Else Output ("Isosceles") EndIf EndIfElse Output("Not a Triangle")EndIfEnd triangle3
Bu sürümler test açısından ne sağlar?
Mantık daha açık olduğunda:
karar noktaları daha net görülür
test case’leri hangi koşulların tetikleyeceği daha kolay planlanır
Sonraki adımlarda bu örnekleri:
white-box (kod-temelli) test mantığıyla
coverage hedefleriyle birlikte kullanacağız.
NextDate Fonksiyonu
Üçgen problemindeki karmaşıklık, daha çok girdiler ile doğru çıktı arasındaki ilişkinden geliyordu.
NextDate örneğinde ise farklı bir karmaşıklık var:
girdi değişkenleri arasındaki mantıksal ilişkiler (ay–gün–yıl uyumu)
Problem Tanımı
NextDate, üç değişkenli bir fonksiyondur:
month (ay), day (gün), year (yıl)
Çıktı: Girilen tarihten bir sonraki günün tarihi
Girdi Koşulları
Girdiler tamsayıdır ve şu aralıklarda olmalıdır:
c1. 1 ≤ month ≤ 12
c2. 1 ≤ day ≤ 31
c3. 1812 ≤ year ≤ 2012
Geçersiz Değerler ve Geçersiz Kombinasyonlar
Üçgen örneğinde olduğu gibi, tanımı daha net yapmak için:
aralık dışı değerler için çıktı tanımlanır (örn. “month 1..12 aralığında değil”)
geçersiz tarih kombinasyonları için çıktı tanımlanır
(örn. “Haziran 31” gibi)
Hata Mesajları Mantığı
c1/c2/c3 koşullarından biri sağlanmazsa:
ilgili değişken için “aralık dışı” mesajı üretir
(örn. “month 1..12 aralığında değil”)
Gün–ay–yıl kombinasyonu geçersizse:
tek bir genel mesaj üretir: “Invalid Input Date”
Tartışma: NextDate Neden Zor?
NextDate’te iki ana karmaşıklık kaynağı vardır:
Girdi uzayı karmaşıklığı
Ay, gün ve yıl aralıkları
Geçersiz gün–ay kombinasyonları (örn. Haziran 31)
Artık yıl (leap year) kuralı
“Şubat 29” gibi özel durumları doğru yönetmek gerekir
Artık Yıl Neden Var?
Bir yıl tam olarak 365 gün değildir (yaklaşık 365.2422 gün).
“Ek gün” problemini çözmek için artık yıllar kullanılır.
Her 4 yılda bir artık yıl yapsaydık küçük bir hata birikirdi.
Bu yüzden Gregoryen takvim, yüzyıl yıllarında ek bir düzeltme yapar.
Artık Yıl Kuralı (Gregoryen)
Bir yıl artık yıldır:
4’e bölünüyorsa → artık yıl
Ama yıl bir yüzyıl yılıysa (100’e bölünüyorsa) → artık yıl değil
Ancak 400’e de bölünüyorsa → yine artık yıl
Örnekler: - 1992, 1996, 2000 → artık yıl - 1900 → artık yıl değildir
Test Açısından Ek Gözlem: “80/20” Etkisi
Yazılımda sıkça “80/20” durumları görülür:
Aktivitenin büyük kısmı, alanın küçük bir kısmında yoğunlaşır (Zipf’s law)
NextDate’te bu genelde şurada görünür:
Kodun büyük kısmı artık yıl ve girdi doğrulama gibi özel durumlara gider
Sonuç: Test tasarımında “az ama kritik” alanları kaçırmamak gerekir.
NextDate2: Geliştirilmiş Uygulama (Improved Version)
Bu sürüm, NextDate problemini daha “tam” ele alır:
önce girdi doğrulama yapar
sonra ay türüne göre (31/30/Şubat/Aralık) case ile ilerler
Amaç: Test üretirken karar noktalarını açık görmek
Adım 1: Girdi Doğrulama
Kullanıcıdan month, day, year alınır
Aralık kontrolleri yapılır:
1 ≤ day ≤ 31
1 ≤ month ≤ 12
1812 ≤ year ≤ 2012
Hatalı olan alan için mesaj verilir
Tüm koşullar sağlanana kadar tekrar edilir
Do Input(month, day, year) c1 = (1 ≤ day) AND (day ≤ 31) c2 = (1 ≤ month) AND (month ≤ 12) c3 = (1812 ≤ year) AND (year ≤ 2012)If NOT(c1) Then Output("Value of day not in the range 1..31")If NOT(c2) Then Output("Value of month not in the range 1..12")If NOT(c3) Then Output("Value of year not in the range 1812..2012")Until c1 AND c2 AND c3
Adım 2: Ay Bazlı Mantık (Case month Of)
Ayın tipine göre farklı kurallar uygulanır:
31 çeken aylar (Aralık hariç bazıları)
30 çeken aylar
Aralık (yıl geçişi)
Şubat (artık yıl dahil)
Bu yapı test açısından şunu sağlar: “Hangi ay tipinde hangi kural var?” netleşir.
31 Çeken Aylar
day < 31 ise → day + 1
day = 31 ise → day = 1, month = month + 1
Case 1: month is 1,3,5,7,8,10If day < 31 Then tomorrowDay = day + 1Else tomorrowDay = 1 tomorrowMonth = month + 1 EndIf
30 Çeken Aylar
day < 30 ise → day + 1
day = 30 ise → day = 1, month = month + 1
day > 30 ise → Invalid Input Date
Case 2: month is 4,6,9,11If day < 30 Then tomorrowDay = day + 1ElseIf day = 30 Then tomorrowDay = 1 tomorrowMonth = month + 1Else Output("Invalid Input Date") EndIf EndIf
Aralık (December) ve Yıl Geçişi
day < 31 ise → day + 1
day = 31 ise → day = 1, month = 1, year = year + 1
En üst yıl sınırı (2012) için ayrıca geçersizlik üretilebilir
Şubat (February) ve Artık Yıl
Şubat günleri:
normal yıl: 28
artık yıl: 29
day = 28 veya day = 29 durumlarında “yarın” hesabı artık yıl kuralına bağlıdır
day > 29 ise → Invalid Input Date
Case 4: month is 2 ...If (year is a leap year) Then ...Else ... EndIf
Örnek Test Senaryoları
Normal durumlar:
15 Mart 2023 → 16 Mart 2023
30 Nisan 2023 → 1 Mayıs 2023
Artık yıl durumları:
28 Şubat 2024 → 29 Şubat 2024
29 Şubat 2024 → 1 Mart 2024
Sınır durumları:
31 Aralık 2023 → 1 Ocak 2024
1 Ocak 2000 → 2 Ocak 2000
Geçersiz durumlar:
31 Nisan 2023 → Invalid Input Date
29 Şubat 2023 → Invalid Input Date
Sözde Kod (Simple Version)
Program NextDate1 'Simple versionDim tomorrowDay,tomorrowMonth,tomorrowYear AsIntegerDim day,month,year AsIntegerOutput ("Enter today's date in the form MM DD YYYY")Input (month, day, year)Case month OfCase 1: month Is 1,3,5,7,8, Or 10: '31 day months (except Dec.)If day < 31Then tomorrowDay = day + 1Else tomorrowDay = 1 tomorrowMonth = month + 1 EndIfCase 2: month Is 4,6,9, Or 11 '30 day monthsIf day < 30Then tomorrowDay = day + 1Else tomorrowDay = 1 tomorrowMonth = month + 1 EndIfCase 3: month Is 12: 'DecemberIf day < 31Then tomorrowDay = day + 1Else tomorrowDay = 1 tomorrowMonth = 1If year = 2012Then Output ("2012 is over")Else tomorrow.year = year + 1 EndIf EndIfCase 4: month is 2: 'FebruaryIf day < 28Then tomorrowDay = day + 1ElseIf day = 28ThenIf ((year is a leap year)Then tomorrowDay = 29 'leap yearElse'not a leap year tomorrowDay = 1 tomorrowMonth = 3 EndIfElseIf day = 29ThenIf ((year is a leap year)Then tomorrowDay = 1 tomorrowMonth = 3Else'not a leap year Output("Cannot have Feb.", day) EndIf EndIf EndIfEndIfEndIfEndCaseOutput ("Tomorrow's date is", tomorrowMonth, tomorrowDay, tomorrowYear)End NextDate
Sözde Kod (Improved Version)
Program NextDate2 'Improved versionDim tomorrowDay,tomorrowMonth,tomorrowYear AsIntegerDim day,month,year AsIntegerDim c1, c2, c3 AsBooleanDo Output ("Enter today's date in the form MM DD YYYY") Input (month, day, year) c1 = (1 <= day) AND (day <= 31) c2 = (1 <= month) AND (month <= 12) c3 = (1812 <= year) AND (year <= 2012)If NOT(c1)Then Output("Value of day not in the range 1..31") EndIfIf NOT(c2)Then Output("Value of month not in the range 1..12") EndIfIf NOT(c3)Then Output("Value of year not in the range 1812..2012") EndIfUntil c1 AND c2 AND c2Case month OfCase 1: month Is 1,3,5,7,8, Or 10: '31 day months (except Dec.)If day < 31Then tomorrowDay = day + 1Else tomorrowDay = 1 tomorrowMonth = month + 1 EndIfCase 2: month Is 4,6,9, Or 11 '30 day monthsIf day < 30Then tomorrowDay = day + 1ElseIf day = 30Then tomorrowDay = 1 tomorrowMonth = month + 1Else Output("Invalid Input Date") EndIf EndIfCase 3: month Is 12: 'DecemberIf day < 31Then tomorrowDay = day + 1Else tomorrowDay = 1 tomorrowMonth = 1If year = 2012Then Output ("Invalid Input Date")Else tomorrow.year = year + 1 EndIf EndIfCase 4: month is 2: 'FebruaryIf day < 28Then tomorrowDay = day + 1ElseIf day = 28ThenIf (year is a leap year)Then tomorrowDay = 29 'leap dayElse'not a leap year tomorrowDay = 1 tomorrowMonth = 3 EndIfElseIf day = 29ThenIf (year is a leap year)Then tomorrowDay = 1 tomorrowMonth = 3ElseIf day > 29Then Output("Invalid Input Date") EndIf EndIf EndIf EndIf EndIfEndCaseOutput ("Tomorrow's date is", tomorrowMonth, tomorrowDay, tomorrowYear)End NextDate2
Test Açısından Mesaj
Bu örnekte kodun büyük kısmı iki yere gider:
girdi doğrulama
artık yıl / Şubat özel durumu
Yani test setinde de bu bölgeler özellikle hedeflenmelidir.
Mini Soru
Bu kod yapısına göre test tasarlarken:
Hangi testler “aralık doğrulama”yı hedefler?
Hangi testler “ay tipi” dallarını hedefler?
Hangi testler “artık yıl” ayrımını hedefler?
Commission Problemi
Üçüncü örnek, ticari uygulamalara daha yakındır.
Hem hesaplama hem karar verme içerir → test açısından ilginçtir.
Problem Tanımı
Bir satış temsilcisi ay boyunca üç ürün kalemi satar:
Kilit (lock): $45
Dipçik (stock): $30
Namlu (barrel): $25
Aylık satışın kısıtları:
Ay içinde en fazla: 70 kilit, 80 dipçik, 90 namlu
Temsilci her ziyaret (şehir) sonrası adetleri bildirir
Ay sonunda satışın bittiğini göstermek için -1 kilit bilgisi gönderilir (bitirme işareti)
Komisyon Hesabı (Katmanlı)
Aylık toplam satış tutarı üzerinden:
%10: $1000’a kadar (dahil)
%15: sonraki $800 (yani $1000–$1800 arası)
%20: $1800 üzerindeki kısım
Tartışma
Örnek, hesaplamaları hızlı görünür yapmak için kurgulanmıştır.
Problem üç parçaya ayrılabilir:
Girdi/veri toplama (ziyaret bazlı adetler + bitirme işareti)
Satış tutarı hesabı
Komisyon hesabı
Bu örnekte:
Girdi doğrulama kısmı (önceki örneklerdeki gibi) detaylandırılmayabilir
MIS (Management Information Systems) tarzı uygulamalarda görülen sentinel-controlled while (bitirme işaretiyle döngü) yaklaşımı vurgulanır
Uygulama: Commission Programı (Genel Akış)
Bu uygulamada üç ana parça var:
Veri toplama (sentinel ile biten döngü)
Satış tutarı hesabı
Komisyon hesabı (katmanlı oran)
Değişkenler ve Sabitler
Ürün adetleri:
locks, stocks, barrels
Birim fiyatlar:
lockPrice = 45, stockPrice = 30, barrelPrice = 25
Toplam adetler:
totalLocks, totalStocks, totalBarrels
Satış tutarları:
lockSales, stockSales, barrelSales, sales
Komisyon:
commission
Sentinel-Controlled Döngü (Bitirme İşareti)
locks = -1 değeri, “veri girişi bitti” anlamına gelir.
Bu değer gelene kadar döngü sürer ve toplamlar birikir.