因此,我现在正在建立我的第一个Django项目,这是一个两人的国际象棋网站。我快要完成了,现在我正在写测试。该项目有两个原始型号:玩家和游戏。播放器模型对用户模型,player.user和game player.current_game的外键具有一对一字段,该键指示玩家当前所在的游戏实例。(默认值)," W"或" B",表明是否提供了抽奖以及提供抽奖的颜色。我有一个测试案例,可以执行以下操作:
class Draw_ViewTestCase(TestCase):
def setUp(self):
self.user1 = User.objects.create_user(username="Test_User_1", password="test1")
self.user2 = User.objects.create_user(username="Test_User_2", password="test2")
self.factory = RequestFactory()
self.game = Game.objects.create()
self.player1 = Player.objects.create(user=self.user1, current_game=self.game, color="w")
self.player2 = Player.objects.create(user=self.user2, current_game=self.game, color="b")
def test_draw(self):
request = self.factory.get(reverse('draw'))
request.user = self.user1
#The draw view changes the draw_offered field of the player's current game to the player's color, and saves the current_game to the database
response = draw(request)
self.game.refresh_from_db()
assert self.game.draw_offered == self.player1.color
assert self.game == self.player2.current_game
#self.player2.current_game.refresh_from_db()
assert self.game.draw_offered == self.player2.current_game.draw_offered
所有的断言都通过了,但最后一个断言,但是如果您将第二行的删除到最后一行,则会通过。
发生了什么事?据我了解,当您引用forefer键属性self.player2.current_game时,django执行数据库查找并返回具有最新字段的游戏实例。因为self.game and self.player2.current_game刚刚调用了数据库中的同一游戏记录,而self.game.game.refresh_from_db()刚刚被调用,您会认为self.game.game_ffered == == self.player.player.player.play.current_game.draw_game.draw_offered将评估为true-两个游戏实例是指相同的数据库记录并具有最新字段。我必须称呼self.player2.current_game.refresh_from_db()才能使断言通行证对我来说没有意义 - 根据我对Django外国键的理解,self.player.player2.current_game应该自动保持最新状态。使用数据库。
这与外国密钥无关。
您缺少的是,仅仅是因为两个实例指向相同的数据库记录,这并不意味着它们是相同的对象。正如您必须刷新self.game
以查看draw
视图中基础记录所做的更改一样,您还需要刷新self.player2.current_game
,以便它也获得这些更新的值。
django如果认为它已经拥有它,则不会拨打数据库来查找外键:因为您最初通过传递整个游戏对象而创建了self.player1
和self.player2
。因此,是的,您需要明确刷新Current_game对象以查看所做的更改。
如果您真的想要,可以通过传递ID而不是完整对象来创建对象:self.player2 = Player.objects.create(...current_game_id=self.game.id...)
。这样,Django实际上就不会受到对象的缓存,因此它需要在测试结束时查询它。
测试跑者将在每个测试之前运行setUp
方法,因此您从运行代码之前就可以在实例上操作。它在Unitest
文档中得到了很好的解释。
您无法从数据库中访问新鲜的player2
实例,只需加载它即可,如setUp
方法中所定义的那样。