Kurs
Birim testi, kaynak kodunun tek tek birimlerinin kullanıma uygun olup olmadığını belirlemek için çeşitli testlere tabi tutulduğu bir yazılım test etme yöntemidir. Kodunuzun kalitesini belirler ve güvence altına alır.
Genel olarak, geliştirme süreci tamamlandığında, geliştirici bilinen ve potansiyel olarak pratik ve faydalı olan ölçütleri veya sonuçları test betiğine kodlar ve belirli bir birimin doğruluğunu doğrular. Test vakası çalıştırma sırasında, çeşitli çerçeveler herhangi bir ölçütü karşılamayan testleri günlüğe kaydeder ve bunları bir özet halinde raporlar.
Geliştiricilerin, her bölümün veya birimin tasarıma uygun olduğunu ve beklendiği gibi davrandığını garanti eden otomatik test betikleri yazması beklenir.
Python Birim Testi
Kodunuz için manuel testler yazmak kesinlikle zahmetli ve zaman alıcı olsa da, Python'un yerleşik birim testi çerçevesi hayatı oldukça kolaylaştırır.
Python'daki birim test çerçevesi, Python ile birlikte paketlenen unittest olarak adlandırılır.
Birim testi, kodunuzun geleceğe dönük olmasını sağlar; çünkü kodunuzun potansiyel olarak başarısız olabileceği veya hata üretebileceği durumları önceden tahmin edersiniz. Tüm durumları öngöremeseniz de çoğunu ele alırsınız.
Bir birim çeşitli kategorilere ayrılabilir:
- Tüm bir modül,
- Tek bir fonksiyon,
- Sınıf veya yöntem gibi eksiksiz bir arayüz.
Kodunuz için birim testleri yazmanın en iyi yolu, önce kodunuzun sahip olabileceği en küçük test edilebilir birimle başlayıp, ardından diğer birimlere geçmek ve o en küçük birimin diğer birimlerle nasıl etkileştiğine bakmaktır; bu şekilde uygulamalarınız için kapsamlı bir birim testi oluşturabilirsiniz.
Python'un birim test çerçevesi Java'nın JUnit'inden esinlenmiştir ve diğer dillerdeki başlıca birim test çerçeveleriyle benzer özelliklere sahiptir. Python'un birim test çerçevesi çeşitli özellikler sunar; bunlar arasında şunlar yer alır:
- Test otomasyonu
- Testler için kurulum ve kapatma kodunun paylaşımı
- Testlerin koleksiyonlar hâlinde bir araya getirilmesi
- Testlerin raporlama çerçevesinden bağımsızlığı
Şimdi bir örnek ele alalım ve neden kodunuz için birim testine ihtiyacınız olduğunu anlayalım.
Python unittest ile Başlarken
Aşağıda, Python'un unittest çerçevesini kullanmanız için gereken adımları özetledik
Küp fonksiyonu oluşturma
Python'da bir küpün hacmini hesaplamak için bir kod yazalım
def cuboid_volume(l):
return (l*l*l)
length = [2,1.1, -2.5, 2j, 'two']
for i in range(len(length)):
print ("The volume of cuboid:",cuboid_volume(length[i]))
The volume of cuboid: 8
The volume of cuboid: 1.3310000000000004
The volume of cuboid: -15.625
The volume of cuboid: (-0-8j)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-67e1c37a435f> in <module>
1 for i in range(len(length)):
----> 2 print ("The volume of cuboid:",cuboid_volume(length[i]))
<ipython-input-2-f50464fd88da> in cuboid_volume(l)
1 def cuboid_volume(l):
----> 2 return (l*l*l)
TypeError: can't multiply sequence by non-int of type 'str'
Sonuç analizi
Yukarıdaki çıktı, kodunuz için birim testinin önemine dair size sezgisel bir fikir vermelidir. Şimdi, yukarıdaki kodda kesinlikle yanlış olan üç şey var:
- İlk olarak, dikdörtgen prizmanın hacmi negatif,
- İkinci olarak, dikdörtgen prizmanın hacmi karmaşık bir sayı,
- Son olarak, kod bir
TypeErrorile sonuçlanıyor; çünkü bir dize, yani tamsayı olmayan bir değer çarpılamaz.
Üçüncü sorun neyse ki bir hataya yol açtı; ancak birinci ve ikinci, dikdörtgen prizmanın hacmi negatif veya karmaşık sayı olamayacağı hâlde yine de başarılı oldu.
Birim testleri genellikle ayrı bir dosyada ayrı bir kod olarak yazılır ve izleyebileceğiniz farklı adlandırma kuralları olabilir. Birim test dosyasının adını, alt çizgiyle ayrılmış kod/birim adı + test şeklinde veya yine alt çizgiyle ayrılmış test + kod/birim adı şeklinde yazabilirsiniz.
Örneğin, yukarıdaki kod dosyasının adı cuboid_volume.py ise, birim test kodunuzun adı cuboid_volume_test.py olabilir
Daha fazla uzatmadan, yukarıdaki kod için birim testi yazalım.
assertAlmostEqual kullanma
Önce volume_cuboid.py adında, hacmi hesaplama kodunu içeren bir Python dosyası ve test_volume_cuboid.py adında, birim test kodunu içeren ikinci bir dosya oluşturalım.
import unittest
TestCuboid sınıfı, unittest modülünden miras alır ve bu sınıfta, birim testinizin cuboid_volume fonksiyonunuzla kontrol etmesini istediğiniz çeşitli yöntemleri tanımlarsınız.
Tanımlayacağınız ilk fonksiyon test_volume olacak; bu, cuboid_volume fonksiyonunuzun verdiği çıktının beklediğiniz değere eşit olup olmadığını kontrol eder. Bunu başarmak için assertAlmostEqual yöntemini kullanacaksınız.
Test 1
class TestCuboid(unittest.TestCase):
def test_volume(self):
self.assertAlmostEqual(cuboid_volume(2),8)
self.assertAlmostEqual(cuboid_volume(1),1)
self.assertAlmostEqual(cuboid_volume(0),0)
self.assertAlmostEqual(cuboid_volume(5.5),166.375)

Yukarıdaki betiği çalıştıralım. unittest modülünü çalıştırırken -m parametresiyle bir betik olarak çalıştıracaksınız.
!python -m unittest test_volume_cuboid.py
Çıktı:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Harika! İlk birim test kodunuz çalıştı.
Test başarıyla çalıştı ve OK döndürdü; bu, cuboid_volume fonksiyonunun beklediğiniz gibi çalıştığı anlamına gelir.
Test 2
Şimdi assertAlmostEqual yöntemlerinden birinin başarısız olduğunda ne olduğunu görelim.

Son doğrulama ifadesinin değiştirildiğine dikkat edin.
!python -m unittest test_volume_cuboid.py
Çıktı:
F
======================================================================
FAIL: test_volume (test_volume_cuboid.TestCuboid)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\hda3kor\Documents\Unit_Testing_Python\test_volume_cuboid.py", line 15, in test_volume
self.assertAlmostEqual(cuboid_volume(5.5),0)
AssertionError: 166.375 != 0 within 7 places (166.375 difference)
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (failures=1)
Yukarıdaki çıktıya bakılırsa, son doğrulama ifadesi bir AssertionError ile sonuçlandı ve bu nedenle birim testi başarısız oldu. Python'un birim test modülü, kodunuzdaki başarısızlığın nedenini ve başarısızlık sayısını gösterir.
assertRaises kullanma
Şimdi başka bir doğrulama yöntemini, yani assertRaises'ı inceleyelim; bu, cuboid_volume fonksiyonunuzun girdi değerlerini doğru şekilde ele alıp almadığını bulmanıza yardımcı olur.
Diyelim ki cuboid_volume fonksiyonunuzun girişin sınıfını veya türünü ele alıp almadığını test etmek istiyorsunuz; örneğin bir dizeyi girdi olarak verirseniz, bunu bir istisna olarak mı ele alacak yoksa bir if koşuluyla mı yönetecek? Çünkü dikdörtgen prizmanın uzunluğu asla bir dize olamaz.

!python -m unittest test_volume_cuboid.py
Çıktı:
F.
======================================================================
FAIL: test_input_value (test_volume_cuboid.TestCuboid)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\hda3kor\Documents\Unit_Testing_Python\test_volume_cuboid.py", line 17, in test_input_value
self.assertRaises(TypeError, cuboid_volume, True)
AssertionError: TypeError not raised by cuboid_volume
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)
Harika! Yukarıdaki çıktıya göre, volume_cuboid.py kodunuz kendisine geçirilen girdiyi düzgün şekilde ele almıyor.
Küp fonksiyonunu değiştirme
volume_cuboid.py içine, girişin veya dikdörtgen prizmanın uzunluğunun boolean ya da dize olup olmadığını kontrol eden ve hata fırlatan bir koşul ekleyelim.

!python -m unittest test_volume_cuboid.py
Çıktı:
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
Python Test Betiğini Jupyter Lab'de Çalıştırma
Şimdi test betiğini Jupyter Lab içinde çalıştıralım. Bunu başarmak için önce, aşağıda gösterildiği gibi test betiğini Jupyter Lab içinde tanımlayacaksınız.
# -*- coding: utf-8 -*-
"""
Created on Sat Apr 25 20:16:58 2020
@author: Aditya
"""
from volume_cuboid import *
import unittest
class TestCuboid(unittest.TestCase):
def test_volume(self):
self.assertAlmostEqual(cuboid_volume(2),8)
self.assertAlmostEqual(cuboid_volume(1),1)
self.assertAlmostEqual(cuboid_volume(0),1)
def test_input_value(self):
self.assertRaises(TypeError, cuboid_volume, True)
Ardından, test betiğini çalıştırmak için unittest.main() yöntemini kullanacaksınız; bu yönteme birkaç argüman geçebilirsiniz; bunlardan biri de ayrıntı düzeyi (verbosity)dir.
Farklı ayrıntı düzeylerini deneyelim ve çıktı açıklamasını nasıl değiştirdiğini görelim.
Verbosity 0
unittest.main(argv=[''],verbosity=0, exit=False)
Output:
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
<unittest.main.TestProgram at 0x1de02774348>
Verbosity 1
unittest.main(argv=[''],verbosity=1, exit=False)
Output:
..
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
<unittest.main.TestProgram at 0x1de027a1cc8>
Verbosity 2
unittest.main(argv=[''],verbosity=2, exit=False)
Output:
test_input_value (__main__.TestCuboid) ... ok
test_volume (__main__.TestCuboid) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
<unittest.main.TestProgram at 0x1de027a8308>
AssertionError'ı görselleştirme
Son olarak, test_volume yöntemindeki son assertAlmostEqual ifadesini değiştirelim ve ayrıntı düzeyi 2'nin yöntem hatasını nasıl gösterdiğini analiz edelim.
# -*- coding: utf-8 -*-
"""
Created on Sat Apr 25 20:16:58 2020
@author: Aditya
"""
from volume_cuboid import *
import unittest
class TestCuboid(unittest.TestCase):
def test_volume(self):
self.assertAlmostEqual(cuboid_volume(2),8)
self.assertAlmostEqual(cuboid_volume(1),1)
self.assertAlmostEqual(cuboid_volume(0),1)
def test_input_value(self):
self.assertRaises(TypeError, cuboid_volume, True)
unittest.main(argv=[''],verbosity=2, exit=False)
Çıktı:
test_input_value (__main__.TestCuboid) ... ok
test_volume (__main__.TestCuboid) ... FAIL
======================================================================
FAIL: test_volume (__main__.TestCuboid)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<ipython-input-28-46ad33b909ee>", line 14, in test_volume
self.assertAlmostEqual(cuboid_volume(0),1)
AssertionError: 0 != 1 within 7 places (1 difference)
----------------------------------------------------------------------
Ran 2 tests in 0.003s
FAILED (failures=1)
<unittest.main.TestProgram at 0x1de027b5448>
Özet
Yukarıdaki çıktılardan şu sonuçlar çıkarılabilir:
- Ayrıntı düzeyi 0, yalnızca kaç testin çalıştırıldığını (ör. 2 test) ve bunların çalıştırılmasının ne kadar sürdüğünü gösterir,
- Ayrıntı düzeyi 1, iki testin çalıştırıldığını belirten iki nokta .. ekler,
- Ayrıntı düzeyi 2, çalıştırılan ayrıntılı yöntem adlarını ve durumlarını
OKveyaFAILolarak gösterir.
Kullanılabilir unittest Doğrulama (Assert) Yöntemleri
Python'un birim test modülünde test amaçlarınız için yararlanabileceğiniz pek çok doğrulama yöntemi vardır.
Yaygın olarak kullanılan doğrulama yöntemleri

Kaynak: unittest belgeleri
Üretim kontrolleri
Aşağıdaki yöntemleri kullanarak istisna, uyarı ve günlük mesajlarının üretilmesini kontrol edebilirsiniz.

Kaynak: unittest belgeleri
Göreve özgü yöntemler

Kaynak: unittest belgeleri
assert yöntemleri hakkında ayrıntılı bilgi için Python'un resmî belgelerine göz atın.
Bunları Pydoc modülünün yardımıyla da öğrenebilirsiniz; bu, Python'daki help fonksiyonuna benzer. assertCountEqual yönteminin belgelerini okumak için Pydoc modülünü nasıl kullanabileceğinize dair bir gösterim aşağıda yer alıyor.
!python -m pydoc unittest.TestCase.assertCountEqual
Çıktı:
Help on function assertCountEqual in unittest.TestCase:
unittest.TestCase.assertCountEqual = assertCountEqual(self, first, second, msg=None)
An unordered sequence comparison asserting that the same elements,
regardless of order. If the same element occurs more than once,
it verifies that the elements occur the same number of times.
self.assertEqual(Counter(list(first)),
Counter(list(second)))
Example:
- [0, 1, 1] and [1, 0, 1] compare equal.
- [0, 0, 1] and [0, 1] compare unequal.
Sonuç
Bu eğitim, Python'da birim testine ve bir geliştirici olarak önemine dair temel bir giriş niteliğindeydi. Sizin için iyi bir egzersiz, geçmiş projelerinizden herhangi biri için bir birim testi modülü yazmak olacaktır. Bu, birim testleri yazma konusunda iyi bir uygulama deneyimi sağlar. Ayrıca kalan Assert yöntemlerini keşfetmeyi de deneyin. Birim test hakkında daha fazlasını şu içeriğimizle okuyabilirsiniz: Pytest eğitimi.
Python'a yeni başlıyorsanız ve daha fazlasını öğrenmek istiyorsanız, şu kursumuzu alın: Python ile Veri Bilimine Giriş.
Sertifikalı bir veri bilimcisi olarak, yenilikçi makine öğrenimi uygulamaları oluşturmak için en son teknolojileri kullanmaya büyük ilgi duyuyorum. Konuşma tanıma, veri analizi ve raporlama, MLOps, konuşma yapay zekası ve NLP alanlarında güçlü bir geçmişe sahip olarak, gerçek bir etki yaratabilecek akıllı sistemler geliştirme becerilerimi geliştirdim. Teknik uzmanlığımın yanı sıra, karmaşık kavramları açık ve özlü bir dille ifade etme yeteneğine sahip, becerikli bir iletişimciyim. Sonuç olarak, veri bilimi konusunda aranan bir blog yazarı oldum ve giderek büyüyen veri profesyonelleri topluluğuyla görüşlerimi ve deneyimlerimi paylaşıyorum. Şu anda, içerik oluşturma ve düzenlemeye odaklanıyorum. Büyük dil modelleriyle çalışarak, hem işletmelerin hem de bireylerin verilerinden en iyi şekilde yararlanmalarına yardımcı olabilecek güçlü ve ilgi çekici içerikler geliştiriyorum.

