Alıştırma

Tamamlandı

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

  1. 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şkenini command kullanarak bir listeyi giriş olarak alır ve isteğe bağlı olarak listeye ön ekini olarak sudokullanabilir. sudo Anahtar sözcük bağımsız değişkeni olarak Falseayarlanırsa, giriş olarak verilen komutu döndürür.

  2. 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şkenin result içinde komutu yoktur sudo ve 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.

  1. admin_command() bir komut istenirken değiştirilen sonucun kullanılması için işlevi liste işlemini döndürecek şekilde sudo gü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 command
    
  2. Pytest ile testi yeniden çalıştırın. Pytest ile bayrağını kullanarak çıkışın ayrıntı düzeyini artırmayı -v deneyin:

    $ pytest -v test_exercise.py
    
  3. Ş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.

  1. İ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çeveden pytest bir 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)
    
  2. 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 TypeError kadar iyidir, ancak kodu yararlı bir hata iletisiyle eklemek iyi olabilir.

  3. İş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 command
    
  4. Son 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 . kullanarak error.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çeren admin_command() bir özel durum.
  • Yardımcı TestAdminCommand() yöntemi ve işlevi denetleyen command() üç test yöntemine sahip bir admin_command() test sınıfı.

Terminalde çalıştırdığınızda tüm testler hata olmadan geçmelidir.