2017-02-22 4 views
2

Я пытаюсь высмеять os.environ внутри класса, но я просто не могу понять это правильно. Вот моя структура:Python mock os.environ, используемый внутри класса

#file.py 
import os 

class MyClass(): 
    connection_url = os.environ['DB'] 

#some code 

А вот мой тест (последняя попытка, так или иначе):

#test.py 
from unittest import TestCase 
from unittest.mock import patch 
from file import MyClass 

class TestMyClass(TestCase): 
    @patch.dict('file.os.environ', {'DB' : 'Dummy' }) 
    def setUp(self): 
     self.class = MyClass() 

#some testing 

Это провал с треском, поднимая KeyError 'DB' ... Может кто-нибудь мне помочь? Я новичок в python unittesting. Я исследовал некоторые блоги и stackoverflow, пробовал некоторые решения, но не мог понять.

Заранее благодарен!

ответ

1

Проблема заключается в том, что connection_url задается при создании класса (при импорте). Если вы хотите, чтобы дразнить его, вы можете пропатчить атрибут самого класса, прежде чем использовать что атрибут:

class TestMyClass(TestCase): 
    @patch.object(file.MyClass, 'connection_url', 'Dummy') 
    def setUp(self): 
     self.instance = MyClass() 

Вы все еще будете иметь дело с потенциальным KeyError во время импорта - то есть вы» вам нужно убедиться, что ваш тестовый бегун имеет фиктивное значение в среде перед вами импортировать файл, иначе вам нужно будет изменить код в file.py, чтобы убедиться, что он не поднимает KeyError. Здесь есть несколько стратегий. Вы можете просто подавить KeyError позволяя connection_url = default_value, если он не был установлен в окружающей среде:

Или вы можете переместить connection_url забирающий в __init__:

class MyClass(): 
    def __init__(self): 
     connection_url = os.environ['DB'] 

Этот последний код имеет дополнительное преимущество, что ваш patch.dict должен начать работать.

Обратите внимание, что если вы выберете один из первых двух подходов, экземпляр будет иметь только исправленный connection_url во время метода setUp. Последующие тесты не будут исправлены. Вполне вероятно, что это будет шоу-стоппер, и вам необходимо создать новый экземпляр в каждом тесте, что у вас есть:

class TestMyClass(TestCase): 
    @patch.object(file.MyClass, 'connection_url', 'Dummy') 
    def test_first_thing(self): 
     self.instance = MyClass() 
     ... 

    @patch.object(file.MyClass, 'connection_url', 'Dummy') 
    def test_second_thing(self): 
     self.instance = MyClass() 
     ... 
+0

Я думаю, что это латание неправильного места, потому что 'os.environ [» DB '] 'все равно будет доступен (и, возможно,« KeyError », если он не настроен в тестовом env). Я имею в виду, что код OP увеличивается во время импорта не во время настройки, поэтому этот патч не поможет. – wim

+0

@wim - Абсолютно. Проблема в том, что вы _can't_ действительно исправляете что-то во время импорта. Все, что вы можете сделать, это патч объекта, когда вы собираетесь его использовать. Это заменит любое значение, которое имеет значение 'connection_url', с фиктивным значением, которое хочет OP. Как вы отмечаете, это не мешает «KeyError», если «DB» не находится в среде. Единственный способ - это _set_ 'os.environ' перед импортом какого-либо кода или путем изменения не-тестовый код ... – mgilson

+0

Следовательно, этот ответ не очень полезен. Как только какой-либо метод тестирования попытается использовать 'self.instance', будет восстановлен старый' connection_url'. Я не вижу никакой точки исправления в 'setUp'. С кодом, который мы показали, это потребует либо другого подхода, либо реструктуризации класса. – wim

Смежные вопросы