django,mongodb 및 테스트

더 읽 기
django 에서 테스트 를 쉽게 쓸 수 있 습 니 다.Django TestCase 를 계승 하면 테스트 데이터 베 이 스 를 자동 으로 만 들 고 실행 할 때마다 필요 한 fixture 데 이 터 를 불 러 와 서 모든 테스트 의 초기 상태 가 일치 하고 예측 가능 하도록 합 니 다.그 전 제 는 dbmodel 을 사용 해 야 한 다 는 것 이다.MySQL,Oracle 등 관계 형 데이터 베 이 스 를 사용 하면 문제 가 되 지 않 는 다.현재 상당히 유행 하 는 NoSQL 과 같은 다른 데이터 베 이 스 를 사용 하면 Django TestCase 를 직접 사용 할 수 없습니다.만약 우리 가 django 를 hack 한다 면,Django TestCase 를 사용 할 수도 있 습 니 다.mongodb 의 경우 저 는 django 1.2,1.2 이하 의 버 전 을 사용 할 수 없습니다.저 는 연구 한 적 이 없 지만 hack 도 할 수 있다 고 믿 습 니 다.
django 는 TestRunner 가 있 습 니 다.테스트 를 시작 할 때 fixture 를 불 러 오 는 작업 은 여기 서 합 니 다.기본 TestRunner 는'django.test.simple.Django Test SuiteRunner'이 며,fixture 를 불 러 오 는 실제 호출 은 loaddata 명령 입 니 다.따라서 fixture 의 로드 작업 을 실현 하려 면 가장 간단 한 방법 은 loaddata 명령 을 다시 정의 하여 데 이 터 를 mongodb 에 불 러 오 는 것 입 니 다.아무 앱 이나 선택 하여 아래 에 management 디 렉 터 리 를 만 들 고 management 아래 commands 디 렉 터 리 를 만 든 다음 에 loaddata.py 를 만 듭 니 다.디 렉 터 리 마다 를 만들어 야 합 니 다.init__.py 파일.명령 을 만 드 는 작업 은 여 기 를 참고 할 수 있 습 니 다.일반 fixture 의 형식 은 json 형식 을 사용 할 수도 있 고 xml 로 쓸 수도 있 으 며 일반 텍스트 형식 을 사용 할 수도 있 지만 해석 하기 가 복잡 하고 유연성 이 부족 하기 때문에 json 을 사용 하 는 것 을 추천 합 니 다.loaddata.py 는 대략 다음 과 같 습 니 다.

from optparse import make_option
from django.core.management.base import BaseCommand
from django.db.models import get_apps
from django.utils import simplejson as json
from pymongo.objectid import ObjectId

class Command(BaseCommand):
    help = 'Installs the named fixture(s) in the database.'
    args = "fixture [fixture ...]"

    option_list = BaseCommand.option_list + (
        make_option('--database', action='store', dest='database',
            default='default db', help='Nominates a specific database to load '
                'fixtures into. Defaults to the "default" database.'),
    )

    def handle(self, *fixture_labels, **options):
        app_fixtures = [os.path.join(os.path.dirname(app.__file__), 'fixtures') for app in get_apps()]
        for fixture_label in fixture_labels:
            for fixture_dir in app_fixtures:
                fullpath = os.path.join(fixture_dir, fixture_label)
                if os.path.isfile(fullpath):
                    fixture = open(fullpath, 'r')
                    data = norm_object(json.loads(fixture.read()))
                    self._do_load(data)

json 은 몇 가지 int,string,bool,array,dict 의 몇 가지 데이터 형식 만 있 기 때문에 datetime,ObjectId(이것 은 mongodb 에서 ID 가 기본적으로 사용 하 는 유형)등 복잡 한 유형 을 대표 하려 면 datetime 에 대해 서 는{'$date':'2009/8/3 05:07:23'}을 사용 할 수 있 고 ObjectId 에 대해 서 는{'$oid':'xxxx'}를 사용 하여 표시 할 수 있 습 니 다.이것 은 어떤 전환 이 필요 합 니 다.이것 은 norm 입 니 다.object 에서 완 성 된 것:

def norm_object(data):
    if isinstance(data, dict):
        if data.has_key('$oid'): # ObjectId
            return ObjectId(data[u'$oid'])
        if data.has_key('$date'): # datetime
            return parse_datetime(data['$date'])
        if data.has_key('$ref'): #dbref
            from pymongo.dbref import DBRef
            return DBRef(data['$ref'], ObjectId(data['$id']))
    if isinstance(data, dict):
        return dict( [ (norm_object(k), norm_object(v)) for k, v in data.iteritems() ])
    if isinstance(data, list):
        return [ norm_object(o) for o in data ]
    return data

대do_load 방법 은 fixture 의 데 이 터 를 mongodb 에 불 러 오 는 것 입 니 다.할 말 이 없습니다.유일 하 게 설명 해 야 할 것 은 데 이 터 를 어느 collection 에 불 러 올 지 지정 하면 저 는 fixture 의 모든 데이터 에서 데이터 베 이 스 를 불 러 올 부분 을 제외 하고 도 추가 합 니 다.collection 속성,어떤 collection 에 불 러 올 지 표시 합 니 다.사용자 데이터 의 fixture 가 이 럴 수 있 습 니 다:

[
	{
		"_collection": "user",
		"_id" : { "$oid", "000011112222333344440001" },
		"username" : "marlon",
		"email" : "[email protected]",
		"password" : "sha1$6f90a$a1d2d0526aec9338e2d5ab7406315df849d9efdf",
		"is_active" : true
	}
]

_do_load 방법 은 다음 과 같 습 니 다.

    def _do_load(self, data):
        db = get_db()
        for obj in data:
            col = obj.pop('_collection')
            col = getattr(db, col)
            col.save(obj, save=True)

여기까지 fixture 로 딩 부분 을 실 현 했 습 니 다.테스트 를 실행 하기 전에 fixture 를 불 러 오고 app 디 렉 터 리 에 fixtures 디 렉 터 리 를 만 든 다음 에 해당 하 는 fixture 를 만 듭 니 다.예 를 들 어 users.json.TestCase 에서 fixtures 데 이 터 는 fixture 의 파일 이름 을 가리 키 고 있 습 니 다:

class UserTestCase(DjangoTestCase):
	fixtures = [ 'users.json', 'other fixture...' ]

또한 실행 할 때 테스트 데이터 베 이 스 를 만 들 고 테스트 실행 이 끝 난 후에 데이터 베 이 스 를 드 롭 해 야 합 니 다.실현 도 쉬 워 요.Django Test Suite Runner 를 덮어 쓰 는 setupdatabases 와 teardowndatabases 방법 이면 됩 니 다.

class MongoTestSuiteRunner(DjangoTestSuiteRunner):
    def setup_databases(self, **kwargs):
        self._test_dbname = 'test_' + settings.MONGODB_NAME
        settings.MONGODB_NAME = self._test_dbname

		# do some database intialize work here
		# ...

        return super(MongoTestSuiteRunner, self).setup_databases(**kwargs)

    def teardown_databases(self, old_config, **kwargs):
        conn = get connection ...
        print 'drop mongo database %s...' % self._test_dbname
        conn.drop_database(self._test_dbname)
        
        super(MongoTestSuiteRunner, self).teardown_databases(old_config, **kwargs)

마지막 으로 settings.py 에서 testrunner 를 MongoTest SuiteRunner 로 지정 해 야 합 니 다.

TEST_RUNNER = 'project.utils.test.SATestSuiteRunner'

이 작업 을 마 친 후에 Django TestCase 를 사용 하여 유닛 테스트 를 쓸 수 있 습 니 다.저 는 어떻게 쓰 는 지 가르쳐 주지 않 겠 습 니 다.

좋은 웹페이지 즐겨찾기