答案 0 :(得分:13)
我有类似的问题。但我希望Django绕过为我的一个实例创建一个测试数据库(这不是一个很难的镜像)。按照Mark的建议,我创建了一个自定义测试运行器,如下所示
from django.test.simple import DjangoTestSuiteRunner
class ByPassableDBDjangoTestSuiteRunner(DjangoTestSuiteRunner):
def setup_databases(self, **kwargs):
from django.db import connections
old_names = []
mirrors = []
for alias in connections:
connection = connections[alias]
# If the database is a test mirror, redirect its connection
# instead of creating a test database.
if connection.settings_dict['TEST_MIRROR']:
mirrors.append((alias, connection))
mirror_alias = connection.settings_dict['TEST_MIRROR']
connections._connections[alias] = connections[mirror_alias]
elif connection.settings_dict.get('BYPASS_CREATION','no') == 'no':
old_names.append((connection, connection.settings_dict['NAME']))
connection.creation.create_test_db(self.verbosity, autoclobber=not self.interactive)
return old_names, mirrors
然后我在settings.py,'BYPASS_CREATION':'yes',
最后,我用
配置了一个新的TestRunnerTEST_RUNNER = 'auth.data.runner.ByPassableDBDjangoTestSuiteRunner'
答案 1 :(得分:9)
我建议使用sqlite3进行测试,同时继续使用mysql / postgres / etc进行生产。
这可以通过将其放在您的设置文件中来实现:
if 'test' in sys.argv:
DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}
请参阅Running django tests with sqlite
将在您的django项目主目录中创建一个临时sqlite数据库文件,您将具有写入权限。另一个优点是sqlite3的测试速度更快。但是,如果你使用任何mysql / postgres特定的原始sql(你应该尽量避免使用它),你可能会遇到问题。
答案 2 :(得分:4)
我认为更好的解决方案可能是define your own test runner。
答案 3 :(得分:3)
我将此添加到上面的评论中但它有点丢失 - 最近对webfaction的更改使这更容易。您现在可以创建new private database instances。
按照那里的说明操作,在创建新用户时,请确保授予他们ALTER USER new_username CREATEDB;
的权限。
您可能还应该更改默认的cron设置,这样他们就不会尝试检查此数据库是否已经启动并且频繁运行。
答案 4 :(得分:2)
您可以使用django-nose作为TEST_RUNNER。安装后,如果传递以下环境变量,则不会删除并重新创建数据库(首先自己手动创建)。
REUSE_DB=1 ./manage.py test
您还可以将以下内容添加到settings.py中,这样每次要运行测试时都不必编写REUSE_DB = 1:
os.environ['REUSE_DB'] = "1"
注意:这也将使您的所有表格都保留在数据库中,这意味着测试设置会更快一点,但您必须手动更新表格(或更改模型时,请自行删除并重新创建数据库。
答案 5 :(得分:2)
我重用数据库的变体:
from django.test.simple import DjangoTestSuiteRunner
from django.core.management import call_command
class TestRunner(DjangoTestSuiteRunner):
def setup_databases(self, **kwargs):
from django.db import connections
settings = connections['default'].settings_dict
settings['NAME'] = settings['TEST_NAME']
settings['USER'] = settings['TEST_USER']
settings['PASSWORD'] = settings['TEST_PASSWD']
call_command('syncdb', verbosity=1, interactive=False, load_initial_data=False)
def teardown_databases(self, old_config, **kwargs):
from django.db import connection
cursor = connection.cursor()
cursor.execute('show tables;')
parts = ('DROP TABLE IF EXISTS %s;' % table for (table,) in cursor.fetchall())
sql = 'SET FOREIGN_KEY_CHECKS = 0;\n' + '\n'.join(parts) + 'SET FOREIGN_KEY_CHECKS = 1;\n'
connection.cursor().execute(sql)
答案 6 :(得分:1)
以下是使用Webfaction XML-RPC API创建数据库的django测试套件运行器。请注意,使用API设置数据库可能需要一分钟,而且脚本可能会暂时停滞,只需等待一段时间。
注意:在webfaction服务器中存在控制面板密码存在安全风险,因为有人违反了您的Web服务器SSH可能会接管您的Webfaction帐户。如果这是一个问题,请将USE_SESSKEY设置为True并使用此脚本下方的结构脚本将会话ID传递给服务器。最后一次API调用的会话密钥expires in 1 hour。
文件test_runner.py:在服务器中,您需要配置./manage.py测试以使用WebfactionTestRunner
"""
This test runner uses Webfaction XML-RPC API to create and destroy database
"""
# you can put your control panel username and password here.
# NOTE: there is a security risk of having control panel password in
# the webfaction server, because someone breaching into your web server
# SSH could take over your Webfaction account. If that is a concern,
# set USE_SESSKEY to True and use the fabric script below this script to
# generate a session.
USE_SESSKEY = True
# CP_USERNAME = 'webfactionusername' # required if and only if USE_SESSKEY is False
# CP_PASSWORD = 'webfactionpassword' # required if and only if USE_SESSKEY is False
import sys
import os
from django.test.simple import DjangoTestSuiteRunner
from django import db
from webfaction import Webfaction
def get_sesskey():
f = os.path.expanduser("~/sesskey")
sesskey = open(f).read().strip()
os.remove(f)
return sesskey
if USE_SESSKEY:
wf = Webfaction(get_sesskey())
else:
wf = Webfaction()
wf.login(CP_USERNAME, CP_PASSWORD)
def get_db_user_and_type(connection):
db_types = {
'django.db.backends.postgresql_psycopg2': 'postgresql',
'django.db.backends.mysql': 'mysql',
}
return (
connection.settings_dict['USER'],
db_types[connection.settings_dict['ENGINE']],
)
def _create_test_db(self, verbosity, autoclobber):
"""
Internal implementation - creates the test db tables.
"""
test_database_name = self._get_test_db_name()
db_user, db_type = get_db_user_and_type(self.connection)
try:
wf.create_db(db_user, test_database_name, db_type)
except Exception as e:
sys.stderr.write(
"Got an error creating the test database: %s\n" % e)
if not autoclobber:
confirm = raw_input(
"Type 'yes' if you would like to try deleting the test "
"database '%s', or 'no' to cancel: " % test_database_name)
if autoclobber or confirm == 'yes':
try:
if verbosity >= 1:
print("Destroying old test database '%s'..."
% self.connection.alias)
wf.delete_db(test_database_name, db_type)
wf.create_db(db_user, test_database_name, db_type)
except Exception as e:
sys.stderr.write(
"Got an error recreating the test database: %s\n" % e)
sys.exit(2)
else:
print("Tests cancelled.")
sys.exit(1)
db.close_connection()
return test_database_name
def _destroy_test_db(self, test_database_name, verbosity):
"""
Internal implementation - remove the test db tables.
"""
db_user, db_type = get_db_user_and_type(self.connection)
wf.delete_db(test_database_name, db_type)
self.connection.close()
class WebfactionTestRunner(DjangoTestSuiteRunner):
def __init__(self, *args, **kwargs):
# Monkey patch BaseDatabaseCreation with our own version
from django.db.backends.creation import BaseDatabaseCreation
BaseDatabaseCreation._create_test_db = _create_test_db
BaseDatabaseCreation._destroy_test_db = _destroy_test_db
return super(WebfactionTestRunner, self).__init__(*args, **kwargs)
文件webfaction.py:这是Webfaction API的瘦包装器,它需要可以由test_runner.py(在远程服务器中)和fabfile.py(在本地机器中)导入
import xmlrpclib
class Webfaction(object):
def __init__(self, sesskey=None):
self.connection = xmlrpclib.ServerProxy("https://api.webfaction.com/")
self.sesskey = sesskey
def login(self, username, password):
self.sesskey, _ = self.connection.login(username, password)
def create_db(self, db_user, db_name, db_type):
""" Create a database owned by db_user """
self.connection.create_db(self.sesskey, db_name, db_type, 'unused')
# deletes the default user created by Webfaction API
self.connection.make_user_owner_of_db(self.sesskey, db_user, db_name, db_type)
self.connection.delete_db_user(self.sesskey, db_name, db_type)
def delete_db(self, db_name, db_type):
try:
self.connection.delete_db_user(self.sesskey, db_name, db_type)
except xmlrpclib.Fault as e:
print 'ignored error:', e
try:
self.connection.delete_db(self.sesskey, db_name, db_type)
except xmlrpclib.Fault as e:
print 'ignored error:', e
文件fabfile.py:生成会话密钥的示例结构脚本,仅在USE_SESSKEY = True
时才需要from fabric.api import *
from fabric.operations import run, put
from webfaction import Webfaction
import io
env.hosts = ["webfactionusername@webfactionusername.webfactional.com"]
env.password = "webfactionpassword"
def run_test():
wf = Webfaction()
wf.login(env.hosts[0].split('@')[0], env.password)
sesskey_file = '~/sesskey'
sesskey = wf.sesskey
try:
put(io.StringIO(unicode(sesskey)), sesskey_file, mode='0600')
# put your test code here
# e.g. run('DJANGO_SETTINGS_MODULE=settings /path/to/virtualenv/python /path/to/manage.py test --testrunner=test_runner.WebfactionTestRunner')
raise Exception('write your test here')
finally:
run("rm -f %s" % sesskey_file)
答案 7 :(得分:1)
接受的答案对我不起作用。它已经过时了,它没有使用djano 1.5在我的遗留代码库上运行。
我通过创建替代测试运行器并更改django设置以提供所有必需的配置并使用新的测试运行器来编写blogpost entirely describing how I solved this issue。
答案 8 :(得分:0)
答案 9 :(得分:0)
简单的解决方法:根据需要更改mypackage.py
中的--coverage
。
答案 10 :(得分:0)
使用单元测试时,您需要指定一个sqlite引擎。打开settings.py并添加“ DATABASES”之后的部分:
import sys
if 'test' in sys.argv or 'test_coverage' in sys.argv: #Covers regular testing and django-coverage
DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'
DATABASES['default']['NAME'] = ':memory:'