我试图了解修补程序的工作原理,并使用pytest测试Django视图:
views.py
#include <type_traits>
#include <iostream>
class TypeA {};
class TypeB {};
class TypeAB: public TypeA, public TypeB {};
template <typename T>
struct Container
{
private:
T* ptr;
public:
Container(): ptr{new T{}} {}
template <typename U>
auto get_Type()
-> std::enable_if_t<true == std::is_base_of<U, T>::value, U*>
{ return ptr; }
template <typename U>
auto get_Type()
-> std::enable_if_t<false == std::is_base_of<U, T>::value, U*>
{ return nullptr; }
};
int main ()
{
Container<TypeA> typea;
Container<TypeB> typeb;
Container<TypeAB> typeab;
std::cout << typea.get_Type<TypeA>() << std::endl; //valid pointer
std::cout << typea.get_Type<TypeB>() << std::endl; //nullptr
std::cout << typeb.get_Type<TypeA>() << std::endl; //nullptr
std::cout << typeb.get_Type<TypeB>() << std::endl; //valid pointer
std::cout << typeab.get_Type<TypeA>() << std::endl; //valid pointer
std::cout << typeab.get_Type<TypeB>() << std::endl; //valid pointer
}
test_view.py
from django.contrib.auth.views import LoginView
class MyLoginView(LoginView):
pass
此操作失败,因为此视图调用数据库以使用功能get_current_site()
获取当前站点:
from django.test import RequestFactory
from .views import MyLoginView
rf = RequestFactory()
def test_login(rf):
request = rf.get(reverse('myapp:login'))
response = MyLoginView.as_view()(request)
assert response.status_code == 200
如何模拟Failed: Database access not allowed
以避免数据库命中?
一个想法是与pytest-factoryboy一起使用工厂。
我设法嘲笑get_current_site()
,但我无法深入:
LoginView.get_context_data
解决方案是在名为imported的范围内修补方法beeing:
from django.test import RequestFactory
from .views import MyLoginView
from django.contrib.sites.models import Site
from pytest_factoryboy import register
from unittest.mock import patch
rf = RequestFactory()
class SiteFactory(factory.Factory):
class Meta:
model = Site
register(SiteFactory)
def test_login_social(rf, site_factory):
request = rf.get(reverse('myapp:login'))
with patch(
# 'django.contrib.auth.views.LoginView.get_context_data', # This is wrong
'django.contrib.auth.views.get_current_site', # Solution: Patch where it is imported, this works!
return_value=site_factory(name='example.com'),
):
response = CommunityLoginView.as_view()(request)
assert response.status_code == 200
由于with patch('django.contrib.auth.views.get_current_site')
是context_data
你会怎么做?
答案 0 :(得分:1)
您在这里有两个选择:
pytest
仅允许database access,如果您明确标记了我们将要访问数据库的测试函数。如果没有这些信息,pytest
将在不构建测试数据库的情况下运行测试。我建议使用pytest-django
和提供的装饰器pytest.mark.django_db
。
您已将Site-Framework添加到INSTALLED_APPS
中。该应用程序是可选的,但如果您通过单个Django应用程序提供多个不同的页面,则该实用程序很有用。曾经有一段时间,网站框架是强制性的,但是由于它是可选的,因此我很少在我的INSTALLED_APPS
中加入它。也许您应该将其保留。
编辑:模拟
当然,由于python中的每个对象都是可模拟的(even small numbers),因此模拟也应该起作用。请记住,由于模块/功能is imported已绑定到本地范围,因此必须对其进行修补。
要找到正确的位置,您可以搜索Django source code,查看其用法和正确打补丁的方法,或尝试放入PDB
。我不确定哪种方法可行,但是我为您提供了两种选择:
pytest --pdb
python -m pdb pytest
。这将立即打开调试器,您必须continue
一次。 pytest
现在将运行直到出现第一个异常,并且PDB
将自动开始。您现在可以使用bt
(回溯),u
(步行堆栈),l
(显示源代码)和d
(步行堆栈)来查找数据库访问的位置。
EDIT2:工厂男孩
如果您使用的是factoryboy
,则是否尝试访问数据库取决于build strategy。默认策略为.create()
,它会写入数据库。
如果您使用site_factory.build()
,它应该可以工作,因为这将无法访问您的数据库。