我正在尝试对一个类中没有返回值的函数进行pytest:
# app.py
from utils import DBConnection
class App:
def add_ticket_watcher(self, ticket_key, watcher_name):
if ticket_key is None:
raise ValueError('Ticket key is empty')
instance = DBConnection()
instance.save(ticket_key, watcher_name)
从上面的代码来看,add_ticket_watcher()
是一个没有返回语句的方法。我从这篇文章中了解到,我们可以使用mock来模拟该方法的预期行为。
对于用pytest模拟函数,我发现我们可以使用monkeypatch。
因此,我的方法是为add_ticket_watcher()
:执行两个测试用例
- 测试有效的票证密钥
- 测试无效的票证密钥
我有这样的东西:
# test_app.py
import pytest
from src.app import App
@pytest.fixture
def app():
app = App()
return app
# Positive test case: Setup parameterize test for valid ticket key
add_valid_watcher_data = (
('func_name', 'ticket_key', 'watcher_name', 'expected_result', 'comment'),
[
('add_ticket_watcher', 'TIC-13527', 'someone', None, 'add watcher at valid ticket key'),
]
)
@pytest.mark.parametrize(*add_valid_watcher_data)
def test_add_ticket_watcher(monkeypatch, app, func_name, ticket_key, watcher_name, expected_result, comment):
def mock_add_ticket_watcher(ticket_key, watcher_name):
# Since `add_ticket_watcher()` has no return statement, I'm mocking the result as None
return None
monkeypatch.setattr(app, "add_ticket_watcher", mock_add_ticket_watcher)
# Run each input parameter from add_valid_watcher_data to `add_ticket_watcher()`
watcher = getattr(app, func_name)(ticket_key, watcher_name)
# If watcher has None value, then `add_ticket_watcher()` execution is successful.
assert expected_result == watcher
# Negative test case: Setup parameterize test for invalid ticket key
add_invalid_watcher_data = (
('func_name', 'ticket_key', 'watcher_name', 'exception_message', 'comment'),
[
('add_ticket_watcher', 'TIC-xx', 'someone', 'Ticket key is empty', 'add watcher at invalid ticket key'),
('add_ticket_watcher', None, 'someone', 'Ticket key is empty', 'ticket key has None value'),
]
)
@pytest.mark.parametrize(*add_invalid_watcher_data)
def test_exception_add_ticket_watcher(app, func_name, ticket_key, watcher_name, exception_message, comment):
with pytest.raises(ValueError, match=exception_message):
# Run each input parameter from add_invalid_watcher_data to `add_ticket_watcher()`
getattr(app, func_name)(ticket_key, watcher_name)
在test_add_ticket_watcher()
中,我不确定该断言什么。但是,由于App.add_ticket_watcher(ticket_key, watcher_name)
没有返回语句。我创建了一个mock函数来返回None
。
有没有更好的方法来实现同样的目的?
如何在Pytest中为没有返回语句的方法创建单元测试?
除了chepner提到的内容。您可以使用mock测试logger.info是否被调用。为了测试负面场景,可以使用mock side_effects强制它引发异常,然后可以测试是否调用了logger.exception。
我不熟悉pytest,但熟悉unittest。然而,我会为你的功能写这3个测试(对你现有的功能做一点修改:(
注意:测试方法名称是描述性的,因此,我不会添加额外的注释。
应用程序
from utils import DBConnection
import cx_Oracle
class App:
def add_ticket_watcher(self, ticket_key, watcher_name):
if ticket_key is None:
raise ValueError('Ticket key is empty')
instance = DBConnection()
try:
instance.save(ticket_key, watcher_name)
except Exception as e:
raise cx_Oracle.DatabaseError('Database save failed')
测试应用程序
import unittest
import app
import cx_Oracle
from mock import patch
class TestApp(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.app = app.App()
def test_if_exception_raised_when_ticket_value_is_none(self):
with self.assertRaises(ValueError):
self.app.add_ticket_watcher(None, 'dummyname')
def test_if_dbconnection_save_is_called(self):
with patch('app.DBConnection.save') as mock_dbconn_save:
self.app.add_ticket_watcher(123, 'dummyname')
self.assertTrue(mock_dbconn_save.called)
def test_if_dbconnection_save_raises_error(self):
with patch('app.DBConnection.save', side_effect = Exception) as mock_dbconn_save_exc:
with self.assertRaises(cx_Oracle.DatabaseError):
self.app.add_ticket_watcher(123, 'dummyname')
if __name__ == '__main__':
unittest.main(verbosity=2)