2013-02-04 2 views
1

Django 애플리케이션 용으로 작성한 테스트는 SQLite를 처음 사용하는 초기 개발 과정에서 완벽하게 작동했습니다. 이제 배포 준비가 끝났으니 MySQL 서버를 설치 했으니 까.하지만 지금은 내 테스트 중 일부가 실패하고있다.Django 테스트는 SQLite를 사용하지만 SQLite는 사용하지 않습니다.

마지막으로 실패한 테스트는 기능을 수동으로 테스트 할 때 실패하지 않습니다.

무슨 일이 벌어 질 수 있습니까?

나는 특별한 것을하지 않고있다. 모든 뷰는 데이터베이스 헛소리를하고 응답을 보낸다. 타이밍 관련 (스레딩 또는 기타 없음)은 없습니다.

테스트는 모두 django.test.TestCase에서 상속되며 어떤 픽스처도 사용하지 않습니다.

다음은 실패한 테스트의 예입니다.

class BaseTest(TestCase): 
    def setUp(self): 
     super(BaseTest, self).setUp() 

     self.userCreds = dict(username='test', password='a') 

     # Create an admin user 
     admin = models.User.objects.create_superuser(
      email='', username='admin', password='a') 

     # Create a user and grant them a licence 
     user = models.User.objects.create_user(
      email='[email protected]', first_name="Mister", 
      last_name="Testy", **self.userCreds) 

     profile = models.getProfileFor(user) 
     node = profile.createNode(
      '12345', 'acomputer', 'auser', 
      '[email protected]', '0456 987 123') 

     self.node = node 

class TestClientUIViews(BaseTest): 
    def test_toggleActive(self): 
     url = reverse('toggleActive') + '?nodeId=%s' % self.node.nodeId 

     self.assertFalse(self.node.active) 

     # This should fail because only authenticated users can toggle a node active 
     resp = self.client.get(url) 
     self.assertEqual(resp.status_code, 403) 
     self.assertFalse(self.node.active) 

     # Login and make sure visiting the url toggles the active state 
     self.client.login(**self.userCreds) 
     resp = self.client.get(url) 
     self.assertEqual(resp.status_code, 200) 
     self.assertTrue(self.node.active) 

     resp = self.client.get(url) 
     self.assertEqual(resp.status_code, 200) 
     self.assertFalse(self.node.active) 

그리고 여기처럼 모델이 모습입니다 : 내 로컬 MySQL은 5.5.19 (그래서 그것의 사용 이노)입니다

class Node(models.Model): 
    @property 
    def active(self): 
     ''' 
     Activation state gets explictly tracked in its own table but is 
     exposed as a property for the sake of convenience 
     ''' 
     activations = NodeActivation.objects \ 
      .filter(node=self) \ 
      .order_by('-datetime') 

     try: 
      return activations[0].active 
     except IndexError: 
      return False 

    @active.setter 
    def active(self, state): 
     if self.active != state: 
      NodeActivation.objects.create(node=self, active=state) 

class NodeActivation(models.Model): 
    node = models.ForeignKey("Node") 
    datetime = models.DateTimeField(default=datetimeM.datetime.now) 
    active = models.BooleanField(default=False) 

하지만 5.1을 사용하고 배포 서버에서 동일한 오류를 얻을 .56. 테스트는 스토리지 엔진과 상관없이 실패합니다.

그리고 처음에 언급했듯이 SQLite 데이터베이스를 사용하도록 다시 전환하면 모든 테스트가 다시 통과됩니다.

+0

테스트 기초 클래스에서 파생 된 테스트는 무엇입니까? 예 :'TestCase'. 질문이 클래스 구조로 완성 된 실패한 간단한 테스트로 업데이트하십시오. –

+0

테스트가 실패 할 때 나타나는 오류 메시지는 무엇입니까? 테스트 또는 일부 공장에서 일부 비품을 사용합니까? –

+0

@AustinPhillips - 실패한 테스트 중 하나에서 코드를 추가했습니다. 그것은 결국 실패, 마지막 assertion (코멘트) – Hamish

답변

1

:

@property 
def active(self): 
    ''' 
    Activation state gets explictly tracked in its own table but is 
    exposed as a property for the sake of convenience 
    ''' 
    activations = NodeActivation.objects \ 
     .filter(node=self) \ 
     .order_by('-id') 

    try: 
     return activations[0].active 
    except IndexError: 
     return False 

문제는 사라집니다.

order_by 호출이 변경되었습니다.

레코드가 너무 빨리 생성되어 datetime에 의한 정렬이 결정적이지 않으므로 엉뚱한 동작입니다. 그리고 SQLite는 MySQL보다 느려서 백업 데이터베이스로 사용할 때 문제가되지 않는 것 같습니다.

참고 : 팁을위한 Austin Phillips 덕분에

+0

당신은 여전히''있어야한다고 생각합니다.order_by ('- datetime', '-id')', 다른 사람들에게 날짜순으로 정렬 된 객체를 보여 주기만하면됩니다. –

+1

추 신 : 자신의 답변을 제공하고 동의하는 것이 좋지만, 이미 문제를 해결 한 답변이있는 경우 기존 답변 중 하나를 수락하는 것이 좋습니다. –

2

이제 실제 코드가 공개되면서이 테스트가 실패한 이유에 대해 다음과 같은 가설을 제시 할 것입니다.

NodeActivation 모델이 잘못되었습니다. datetime 필드는 다음과 같아야합니다

datetime = models.DateTimeField(auto_now=True) 

한 번만 평가하는 모델 정의에 datetime.datetime.now() 사용.

세터가 새로운 NodeActivation 레코드를 만들 때마다 동일한 날짜/시간으로 레코드가 만들어집니다. 즉 NodeActivation 모델이 처음 평가 된 날짜/시간.

getter는 단일 결과 만 반환합니다. 그러나 두 활성화 레코드 모두 동일한 날짜/시간을 갖기 때문에 순서는 데이터베이스 백엔드에 따라 달라질 수 있습니다. 테스트가 끝날 때 데이터베이스에 두 개의 NodeActivation 개의 레코드가 있으며, 반환되는 레코드는 불확정합니다. 이에 노드 모델 클래스의 활성 속성을 변경하여

+0

기본 = datetime.datetime.now를 사용하는 이유 (참고 : 함수를 호출하는 결과가 아닌 함수를 전달합니다 - 장고는 새 레코드를 만들 때 호출합니다.) 왜냐하면 시간대를 가져 오는 데 어려움을 겪고 있었기 때문입니다. 데이터베이스와 파이썬 사이의 일치 여부. 이 문제를 해결하는 것은 TODO이지만 테스트가 실패하는 이유는 아닙니다 (방금 확인했습니다 :-)). 또한 나는 그것이 있었다면 SQLite를 뒷받침 DB로 사용하지 못할 것이라고 생각합니다. – Hamish

+1

@Hamish 죄송합니다, 당신 말이 맞아요. 나는'default'가 함수라는 것을 놓쳤다. 그렇더라도 테스트가 빠르게 진행되고 정품 인증 레코드의 'datetime'필드가 동일한 타임 스탬프로 끝나면 getter에서 결과의 순서가 어떻게 보장됩니까? getter에서'order_by'에'-id'를 추가하십시오. 더 나은 방법은 각 단계에서 NodeActivation 테이블의 전체 내용을 덤프하여 가정을 확인하는 것입니다. –

+0

물론! 좋은 생각 @ 오스틴, 고마워. 그게 다야, 정말 고마워! – Hamish

0

(그의 대답에 주석을 체크 아웃) 내가했다 당신이이 같은 설치 방법을 사용하여 PostgreSQL을에 SQLite는에서가 비슷한 문제 (그 같은 있는지 확실하지 않습니다) 초기 데이터베이스 개체.

예 : 나는 (당신이 말한 것처럼 여전히 데이터베이스를 구축 할 것입니다,하지만를 실행할 수 없습니다이 SQLite는에 잘 작동,하지만 PostgreSQL을에 나는 데이터베이스 연결 실패를 얻는 것을 발견

def setUp(self): 
    user = User.objects.create_user(username='john', password='abbeyRd', email='[email protected]') 
    user.save() 

연결 오류없이 테스트).

는 수정이 다음과 같이 설정 방법을 실행하는 것입니다, 알고 보니이 작동하고 다른 하나는하지 않았다 왜

@classmethod 
def setUpTestData(cls): 
    user = User.objects.create_user(username='john', password='abbeyRd', email='[email protected]') 
    user.save() 

나는 정확한 이유를 기억하지 않는다, 그러나 할 수있는 뭔가가 있었다 setUp(self)을 사용하는 경우 모든 테스트를 다시 연결하려는 데이터베이스에 연결하고 setUpTestData(cls)을 사용하면 클래스가 인스턴스화 될 때만 연결되지만 세부 사항은 완벽하지 않을 수 있습니다. 내가 아는 전부는 그것이 효과가있다!

호프가 도움이되었거나 정확한 문제를 해결했는지 확신 할 수 없지만 알아내는 데 몇 시간이 걸렸으므로 나중에 도움이되기를 바랍니다.

관련 문제