2016-07-12 45 views
7

Bir modül için bazı birim testleri uygulamaya çalışıyorum. aşağıdaki gibi alphabet.py adında bir örnek modüldür:Genel değişkene geçiş

import database 

def length_letters(): 
    return len(letters) 

def contains_letter(letter): 
    return True if letter in letters else False 


letters = database.get('letters') # returns a list of letters 

ben seçimimi bazı değerlere sahip bir veritabanından yanıtı alay etmek isteriz, ancak aşağıdaki kod çalışmak için görünmüyor.

import unittests 
import alphabet 
from unittest.mock import patch 


class TestAlphabet(unittest.TestCase): 
    @patch('alphabet.letters') 
    def setUp(self, mock_letters): 
     mock_letters.return_value = ['a', 'b', 'c'] 

    def test_length_letters(self): 
     self.assertEqual(3, alphabet.length_letters()) 

    def test_contains_letter(self): 
     self.assertTrue(alphabet.contains_letter('a')) 

'Yama' uygulamasının yöntemlere ve sınıflara uygulandığı, ancak değişkenlere uygulanmadığı birçok örnek gördüm. database.get yöntemini yamamaya tercih ediyorum çünkü daha sonra farklı parametrelerle tekrar kullanabilirim, bu yüzden farklı bir yanıta ihtiyacım var.

Burada yanlış olan ne yapıyorum?

cevap

2

Sahte kullanmanız gerekmez. Sadece setUp() içinde küresel değerini modülü almak ve değiştirmek:

import alphabet 

class TestAlphabet(unittest.TestCase): 
    def setUp(self): 
     alphabet.letters = ['a', 'b', 'c'] 
+3

Bu yaklaşımın talihsiz bir sonucu, eski değeri depoladığınız ve geri yüklemediğiniz sürece, bu modül düzeyi değişkenini kullanan başka bir testin başarısız olacağıdır. Alay etmek senin için halleder. –

+1

"alphabet.letters" öğesinin değerini, 'tearDown' işlevinde bulunduğuna geri döndürebilirsiniz. – tomas

+0

Ayrıca, 'setUp' tüm test sınıfına dağıtıldığı için, bu değerleri sadece 'letters' için kullanabilirsiniz. Will'in cevabı, farklı test senaryoları için birden fazla alay yapmanıza izin veriyor ve sonunda kendilerini temizliyorlar, bu yüzden tesadüfi test kirliliği riski yoktur. – raindrift

10

bu deneyin:

import unittests 
import alphabet 
from unittest.mock import patch 


class TestAlphabet(unittest.TestCase): 
    def setUp(self): 
     self.mock_letters = mock.patch.object(
      alphabet, 'letters', return_value=['a', 'b', 'c'] 
     ) 

    def test_length_letters(self): 
     with self.mock_letters: 
      self.assertEqual(3, alphabet.length_letters()) 

    def test_contains_letter(self): 
     with self.mock_letters: 
      self.assertTrue(alphabet.contains_letter('a')) 

Tek tek testler aslında sadece setUp() yılında, çalışırken alay uygulamak gerekir. modelini setUp() modelinde oluşturabilir ve daha sonra bir with ... İçerik Yöneticisi ile uygulayabiliriz.

+0

İstediğim şey buydu, ama John'un cevabı verilen örnek için daha iyi görünüyor. Seninkileri diğer durumlarda da faydalı buluyorum. Teşekkür ederim. – Funkatic

+0

Sorun değil, yardım etmekten memnunum! – Will

0

Herhangi bir işlev veya sınıfın dışında kullanılan değişkenlerle uğraşmak için çalıştığım bir soruna rastladım. Bu sorun, sınıfla dalga geçmeye çalıştığınız an için kullanıldığından, değerleri alay etmeden önce.

Bir ortam değişkeni kullanarak bitti. Ortam değişkeni varsa, bu değeri kullanın, aksi halde uygulama varsayılanını kullanın. Bu şekilde testlerimde ortam değişken değerini ayarlayabilirim. Sınıf Benim sınıfımda

os.environ["PROFILER_LOG_PATH"] = "./" 

ithal edilmeden önce benim testte

, bu koda sahip: Varsayılan olarak

log_path = os.environ.get("PROFILER_LOG_PATH",config.LOG_PATH) 

benim config.LOG_PATH/var/log/<my app name> olduğunu, ancak şimdi testi çalışırken, Günlük yolu geçerli dizine ayarlanır. Bu şekilde testleri çalıştırmak için root erişimine ihtiyacınız yoktur.

+1

İdeal olarak, testleriniz herhangi bir ek konfigürasyon olmaksızın tüm ortamlarda aynı olmalıdır. Aksi takdirde yerel makinenizden geçebilir, ancak başka bir yerde başarısız olabilirler. – Funkatic