Djangoのfixtureで登録したユーザーでテストClientのログイン認証に一瞬だけ手間取った話

# 開発環境
* Python 3.9
* Django==3.2.12
* djangorestframework==3.13.1

# 困ったこと。

DjangoでModelSetViewを使ったAPIの開発で、
ログイン認証の必要なAPIのテストをしているとき。

```tests.py
class TestAuthApi(TestCase):
    '''認証APIのテスト'''

    AUTH_URL = '/api-token-auth/' # 認証用URL
    fixtures = ['fixtures/test/test_data.json']
    
    def test_token(self):
        '''POSTメソッドのテスト'''
        client = Client()
        # トークン取得
        token_response = client.post(
            self.AUTH_URL,
            data={
                "username": "testuser",
                "password": "password",
                "email": "testuser@test.com",
            },
            content_type='application/json',
        )
        # トークン認証のチェック
        self.assertEqual(token_response.status_code, 200)
        self.assertTrue('token' in token_response.json())
```
を`python manage.py test`で実行すると、
```
AssertionError: 401 != 200
```
がraiseされた。
認証できていないということですね。

ちゃんと、ユーザー名も、パスワードも、メールアドレスも間違っていないことを確認しているので、なにが間違っているのだろう？
(`python manage.py createsuperuser`で作ったユーザーでは、Webブラウザ、API共に認証できているので、User周りの設定が間違っていることはないだろう。)

### 関連するファイルの関連する箇所

```models.py
from django.contrib.auth.models import AbstractUser
(略)

class User(AbstractUser):
    pass

(略)
```

```serializers.py
from rest_framework import serializers
from django.contrib.auth import get_user_model
(略)

class UserSerializer(serializers.ModelSerializer):
    """ユーザーシリアライザー"""
    class Meta:
        model = get_user_model()
        fields = ('id', 'username', 'email')
(略)
```

```urls.py
from rest_framework.authtoken import views as auth_views
(略)

urlpatterns = [
    (略)
    # トークン認証用エンドポイント
    url(r'^api-token-auth/', auth_views.obtain_auth_token),
]
```


```settings.py
(略)

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework.authtoken',
    (略)
]

(略)

AUTH_USER_MODEL = 'apiv1.User'

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES':[
        'rest_framework.authentication.TokenAuthentication', # トークン認証
        'rest_framework.authentication.SessionAuthentication', # セッション認証
    ]
}

(略)
```

```test_data.json
[
    {
        "model": "アプリ名.user",
        "pk": 1,
        "fields": {
            "username": "testuser",
            "password": "password",
            "email": "testuser@test.com",
            (略)
        }
    },
]
```

# 解決策
「Webブラウザ、APIでは認証できているのに、テストClientでは認証できない。」
→ということは、テスト用データが間違っているのでは？

よくよく考えたら、テスト用データにパスワードの平文を書いたけど、DBに平文が保存されるはずないよね、、、

ということで調べると、Djangoでは`make_password`関数を使って、パスワードをハッシュ化して保存している。

なので、fixtureのデータをパスワードのハッシュ値にすればよい。
ということで、ハッシュ値の取得を行う。
```
# python manage.py shell
>>> from django.contrib.auth.hashers import make_password
>>> make_password('password')
'pbkdf2_sha256$260000$O2CJugvRp7L8GMfcLfv8eZ$X8Mf8PPmtf37Emg2nD42bJ/m3PQF+jYVpgKEifiDbHo='
```
これを、fixtureに入れて、

```test_data.json
[
    {
        "model": "アプリ名.user",
        "pk": 1,
        "fields": {
            "username": "testuser",
            "password": "pbkdf2_sha256$260000$O2CJugvRp7L8GMfcLfv8eZ$X8Mf8PPmtf37Emg2nD42bJ/m3PQF+jYVpgKEifiDbHo=",
            "email": "testuser@test.com",
            (略)
        }
    },
]
```
として、再度`python manage.py test`を実行すると、
#### OK！！！

初歩的なミスでしたが、こういうのを地道に解決していく過程でフレームワークへの理解が深まったりしますよね。
(「テスト用のユーザー登録からやればいいじゃん」というよのは内緒。)

# 参考
https://medium.com/p/64a4b38904ff#9c63
(ちょっと古いけど。)