Alıştırma
Bu alıştırmada, bir işlevi test etmek için Pytest kullanacaksınız. Ardından, başarısız testlere neden olan işlevle ilgili bazı olası sorunları bulur ve düzeltirsiniz. Hatalara bakmak ve Pytest'in zengin hata raporlamasını kullanmak, üretim kodundaki sorunlu testleri veya hataları tanımlamak ve düzeltmek için gereklidir.
Bu alıştırmada, bir sistem komutunu giriş olarak kabul eden ve isteğe bağlı olarak araca ön ekleyen admin_command() adlı sudo bir işlev kullanacağız. İşlev, test yazarak keşfettiğiniz bir hataya sahiptir.
1. Adım - Bu alıştırma için testleri olan bir dosya ekleme
Test dosyaları için Python'ın dosya adı kurallarını kullanarak yeni bir test dosyası oluşturun. Test dosyasını test_exercise.py adlandırın ve aşağıdaki kodu ekleyin:
def admin_command(command, sudo=True): """ Prefix a command with `sudo` unless it is explicitly not needed. Expects `command` to be a list. """ if sudo: ["sudo"] + command return commandİşlev
admin_command(), bağımsız değişkeninicommandkullanarak bir listeyi giriş olarak alır ve isteğe bağlı olarak listeye ön ekini olaraksudokullanabilir.sudoAnahtar sözcük bağımsız değişkeni olarakFalseayarlanırsa, giriş olarak verilen komutu döndürür.Aynı dosyaya işlevin testlerini
admin_command()ekleyin. Testler örnek bir komut döndüren bir yardımcı yöntemi kullanır:class TestAdminCommand: def command(self): return ["ps", "aux"] def test_no_sudo(self): result = admin_command(self.command(), sudo=False) assert result == self.command() def test_sudo(self): result = admin_command(self.command(), sudo=True) expected = ["sudo"] + self.command() assert result == expected
Not
Gerçek kodla aynı dosyada testlerin olması yaygın değildir. Kolaylık olması için, bu alıştırmadaki örneklerde aynı dosyada gerçek kod bulunur. Gerçek dünyadaki Python projelerinde testler genellikle test ettikleri koddan dosya ve dizinlerle ayrılır.
2. Adım - Testleri çalıştırma ve hatayı belirleme
Artık test dosyasının test etmek için bir işlevi ve davranışını doğrulamak için birkaç test olduğuna göre, testleri çalıştırmanın ve hatalarla çalışmanın zamanı geldi.
Dosyayı Python ile yürütür:
$ pytest test_exercise.pyÇalıştırma bir test geçişi ve bir hata ile tamamlanmalıdır ve hata çıkışı aşağıdaki çıkışa benzer olmalıdır:
=================================== FAILURES =================================== __________________________ TestAdminCommand.test_sudo __________________________ self = <test_exercise.TestAdminCommand object at 0x10634c2e0> def test_sudo(self): result = admin_command(self.command(), sudo=True) expected = ["sudo"] + self.command() > assert result == expected E AssertionError: assert ['ps', 'aux'] == ['sudo', 'ps', 'aux'] E At index 0 diff: 'ps' != 'sudo' E Right contains one more item: 'aux' E Use -v to get the full diff test_exercise.py:24: AssertionError =========================== short test summary info ============================ FAILED test_exercise.py::TestAdminCommand::test_sudo - AssertionError: assert... ========================= 1 failed, 1 passed in 0.04s ==========================Çıkış testte
test_sudo()başarısız oluyor. Pytest, karşılaştırılan iki liste hakkında ayrıntılı bilgi veriyor. Bu durumda değişkeninresultiçinde komutu yoktursudove bu da testin beklediği durumdur.
3. Adım - Hatayı düzeltme ve testlerin geçmesini sağlama
Herhangi bir değişiklik yapmadan önce, ilk etapta neden bir hata olduğunu anlamanız gerekir. Beklentinin karşılanmadığını (sudo sonuçta olmadığını) görebilirsiniz ancak nedenini bulmanız gerekir.
Koşul karşılandığında işlevden admin_command() aşağıdaki kod satırlarına sudo=True bakın:
if sudo:
["sudo"] + command
Listelerin işlemi değeri döndürmek için kullanılmaz. Döndürülmüyor olduğundan işlev her zaman olmadan sudo komutu döndürür.
admin_command()bir komut istenirken değiştirilen sonucun kullanılması için işlevi liste işlemini döndürecek şekildesudogüncelleştirin. Güncelleştirilmiş işlev aşağıdaki gibi görünmelidir:def admin_command(command, sudo=True): """ Prefix a command with `sudo` unless it is explicitly not needed. Expects `command` to be a list. """ if sudo: return ["sudo"] + command return commandPytest ile testi yeniden çalıştırın. Pytest ile bayrağını kullanarak çıkışın ayrıntı düzeyini artırmayı
-vdeneyin:$ pytest -v test_exercise.pyŞimdi çıkışı doğrulayın. Şimdi iki geçiş testi göstermelidir:
============================= test session starts ============================== Python 3.9.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 cachedir: .pytest_cache rootdir: /private collected 2 items test_exercise.py::TestAdminCommand::test_no_sudo PASSED [ 50%] test_exercise.py::TestAdminCommand::test_sudo PASSED [100%] ============================== 2 passed in 0.00s ===============================
Not
Fonksiyon daha fazla farklı büyük/küçük harf değerleriyle çalışabildiğinden, bu çeşitlemeleri kapsamak için daha çok test eklenmelidir. Bu, işlevde gelecekteki değişikliklerin farklı (beklenmeyen) bir davranışa neden olmasını engeller.
4. Adım - Testlerle yeni kod ekleme
Önceki adımlarda testleri ekledikten sonra işlevde daha fazla değişiklik yapmayı ve bunları testlerle doğrulamayı rahat hissetmeniz gerekir. Değişiklikler mevcut testlerin kapsamına alınmıyor olsa bile, önceki varsayımları bozmadığınızdan emin olabilirsiniz.
Bu durumda işlev bağımsız değişkenin admin_command() her zaman bir liste olduğuna körü körüne command güvenir. Şimdi yararlı bir hata iletisi içeren bir özel durumun tetiklenmesiyle bunu iyileştirelim.
İlk olarak, davranışı yakalayan bir test oluşturun. İşlev henüz güncelleştirilmemiş olsa da, test öncelikli bir yaklaşımı (Test Odaklı Geliştirme veya TDD olarak da bilinir) deneyin.
-
test_exercise.py dosyasını en üstte içeri aktarabilecek
pytestşekilde güncelleştirin. Bu test, çerçevedenpytestbir iç yardımcı kullanır:
import pytest- Şimdi özel durumu denetlemek için sınıfına yeni bir test ekle. Bu test, geçirilen değer liste olmadığında işlevden bir beklenmelidir
TypeError:
def test_non_list_commands(self): with pytest.raises(TypeError): admin_command("some command", sudo=True)-
test_exercise.py dosyasını en üstte içeri aktarabilecek
Pytest ile testleri yeniden çalıştırın. Hepsi geçmelidir:
============================= test session starts ============================== Python 3.9.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 rootdir: /private/ collected 3 items test_exercise.py ... [100%] ============================== 3 passed in 0.00s ===============================Test, denetlenecek
TypeErrorkadar iyidir, ancak kodu yararlı bir hata iletisiyle eklemek iyi olabilir.İşlevi, yararlı bir hata iletisiyle açıkça yükseltecek
TypeErrorşekilde güncelleştirin:def admin_command(command, sudo=True): """ Prefix a command with `sudo` unless it is explicitly not needed. Expects `command` to be a list. """ if not isinstance(command, list): raise TypeError(f"was expecting command to be a list, but got a {type(command)}") if sudo: return ["sudo"] + command return commandSon olarak, hata iletisini denetlemek için yöntemini güncelleştirin
test_non_list_commands():def test_non_list_commands(self): with pytest.raises(TypeError) as error: admin_command("some command", sudo=True) assert error.value.args[0] == "was expecting command to be a list, but got a <class 'str'>"Güncelleştirilmiş test, tüm özel durum bilgilerini tutan bir değişken olarak kullanır
error. kullanarakerror.value.argsözel durumun bağımsız değişkenlerini araştırabilirsiniz. Bu durumda, ilk bağımsız değişken testin denetleyebileceği hata dizesine sahiptir.
Çalışmanızı denetleyin
Bu noktada şunları içeren test_exercise.py adlı bir Python test dosyanız olmalıdır:
- Bağımsız
admin_command()değişkeni ve anahtar sözcük bağımsız değişkenlerini kabul eden bir işlev. -
TypeErrorİşlevde yararlı bir hata iletisi içerenadmin_command()bir özel durum. - Yardımcı
TestAdminCommand()yöntemi ve işlevi denetleyencommand()üç test yöntemine sahip biradmin_command()test sınıfı.
Terminalde çalıştırdığınızda tüm testler hata olmadan geçmelidir.