1
Fork 0
mirror of https://github.com/Steffo99/sophon.git synced 2024-12-22 14:54:22 +00:00

🧪 Improve tests significantly

This commit is contained in:
Steffo 2021-10-28 09:43:15 +02:00
parent 72d8146765
commit 667bfe9e16

View file

@ -2,11 +2,14 @@ import abc
import contextlib import contextlib
import typing as t import typing as t
import django.urls.exceptions
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.urls import reverse from django.urls import reverse
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
from rest_framework.utils.serializer_helpers import ReturnDict
from . import errors
from . import models from . import models
@ -16,16 +19,29 @@ class BetterAPITestCase(APITestCase):
""" """
@contextlib.contextmanager @contextlib.contextmanager
def as_user(self, username: str, password: str) -> t.ContextManager[None]: def as_user(self, username: str, password: str = None) -> t.ContextManager[None]:
""" """
**Context manager** which runs tests as a specific user. **Context manager** which runs tests as a specific user.
:param username: The username of the user to login as. :param username: The username of the user to login as.
:param password: The password of the user to login as. :param password: The password of the user to login as. If not specified, the username is used as password.
""" """
yield self.client.login(username, password) yield self.client.login(username=username, password=password or username)
self.client.logout() self.client.logout()
def assertData(self, data: ReturnDict, expected: dict):
"""
Assert that the returned data includes the key-value pairs of the second.
:param data: The "larger" dictionary.
:param expected: The "smaller" dictionary.
.. seealso:: https://stackoverflow.com/a/59777678/4334568, https://www.python.org/dev/peps/pep-0584/
"""
# Convert the ReturnDict to a regular dict, otherwise DRF will include some garbage
data = dict(data)
self.assertEqual(data, data | expected)
class ReadSophonTestCase(BetterAPITestCase, metaclass=abc.ABCMeta): class ReadSophonTestCase(BetterAPITestCase, metaclass=abc.ABCMeta):
""" """
@ -51,7 +67,10 @@ class ReadSophonTestCase(BetterAPITestCase, metaclass=abc.ABCMeta):
:return: The URL corresponding to the action with all parameters filled in. :return: The URL corresponding to the action with all parameters filled in.
""" """
basename = cls.get_basename() basename = cls.get_basename()
return reverse(f"{basename}-{action}", args=args, kwargs=kwargs) try:
return reverse(f"{basename}-{action}", args=args, kwargs=kwargs)
except django.urls.exceptions.NoReverseMatch:
raise errors.HTTPException(404)
def list(self) -> Response: def list(self) -> Response:
""" """
@ -63,16 +82,21 @@ class ReadSophonTestCase(BetterAPITestCase, metaclass=abc.ABCMeta):
return self.client.get(url, {}, format="json") return self.client.get(url, {}, format="json")
# I hate how unittest doesn't follow PEP8 when naming methods # I hate how unittest doesn't follow PEP8 when naming methods
def assertActionList(self, code: int = 200) -> t.Any: def assertActionList(self, code: int = 200) -> t.Optional[ReturnDict]:
""" """
Perform the ``list`` action, and assert that it will return a specific status code. Perform the ``list`` action, and assert that it will return a specific status code.
:param code: The expected status code. :param code: The expected status code.
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`. :return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
""" """
response = self.list() try:
self.assertEqual(response.status_code, code, msg=f"`list` did not return {code}") response = self.list()
return response.data or None except errors.HTTPException as exc:
self.assertEqual(exc.status, code, msg=f"`list` did not return {code}: {exc!r}")
return None
else:
self.assertEqual(response.status_code, code, msg=f"`list` did not return {code}: {response.data!r}")
return response.data or None
def retrieve(self, pk) -> Response: def retrieve(self, pk) -> Response:
""" """
@ -84,7 +108,7 @@ class ReadSophonTestCase(BetterAPITestCase, metaclass=abc.ABCMeta):
url = self.get_url("detail", pk=pk) url = self.get_url("detail", pk=pk)
return self.client.get(url, {}, format="json") return self.client.get(url, {}, format="json")
def assertActionRetrieve(self, pk, code: int = 200) -> t.Any: def assertActionRetrieve(self, pk, code: int = 200) -> t.Optional[ReturnDict]:
""" """
Perform the ``retrieve`` action, and assert that it will return a specific status code. Perform the ``retrieve`` action, and assert that it will return a specific status code.
@ -92,9 +116,14 @@ class ReadSophonTestCase(BetterAPITestCase, metaclass=abc.ABCMeta):
:param code: The expected status code. :param code: The expected status code.
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`. :return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
""" """
response = self.retrieve(pk=pk) try:
self.assertEqual(response.status_code, code, msg=f"`retrieve` did not return {code}") response = self.retrieve(pk=pk)
return response.data except errors.HTTPException as exc:
self.assertEqual(exc.status, code, msg=f"`retrieve` did not return {code}: {exc!r}")
return None
else:
self.assertEqual(response.status_code, code, msg=f"`retrieve` did not return {code}: {response.data!r}")
return response.data
class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta): class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta):
@ -112,7 +141,7 @@ class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta):
url = self.get_url("list") url = self.get_url("list")
return self.client.post(url, data, format="json") return self.client.post(url, data, format="json")
def assertActionCreate(self, data, code: int = 201) -> t.Any: def assertActionCreate(self, data, code: int = 201) -> t.Optional[ReturnDict]:
""" """
Perform the ``create`` action, and assert that it will return a specific status code. Perform the ``create`` action, and assert that it will return a specific status code.
@ -120,9 +149,14 @@ class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta):
:param code: The expected status code. :param code: The expected status code.
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`. :return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
""" """
response = self.create(data=data) try:
self.assertEqual(response.status_code, code, msg=f"`create` did not return {code}") response = self.create(data=data)
return response.data except errors.HTTPException as exc:
self.assertEqual(exc.status, code, msg=f"`create` did not return {code}: {exc!r}")
return None
else:
self.assertEqual(response.status_code, code, msg=f"`create` did not return {code}: {response.data!r}")
return response.data
def update(self, pk, data) -> Response: def update(self, pk, data) -> Response:
""" """
@ -135,7 +169,7 @@ class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta):
url = self.get_url("detail", pk=pk) url = self.get_url("detail", pk=pk)
return self.client.put(url, data, format="json") return self.client.put(url, data, format="json")
def assertActionUpdate(self, pk, data, code: int = 200) -> t.Any: def assertActionUpdate(self, pk, data, code: int = 200) -> t.Optional[ReturnDict]:
""" """
Perform the ``update`` action, and assert that it will return a specific status code. Perform the ``update`` action, and assert that it will return a specific status code.
@ -144,9 +178,14 @@ class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta):
:param code: The expected status code. :param code: The expected status code.
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`. :return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
""" """
response = self.update(pk=pk, data=data) try:
self.assertEqual(response.status_code, code, msg=f"`update` did not return {code}") response = self.update(pk=pk, data=data)
return response.data except errors.HTTPException as exc:
self.assertEqual(exc.status, code, msg=f"`update` did not return {code}: {exc!r}")
return None
else:
self.assertEqual(response.status_code, code, msg=f"`update` did not return {code}: {response.data!r}")
return response.data
def destroy(self, pk) -> Response: def destroy(self, pk) -> Response:
""" """
@ -158,7 +197,7 @@ class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta):
url = self.get_url("detail", pk=pk) url = self.get_url("detail", pk=pk)
return self.client.delete(url, {}, format="json") return self.client.delete(url, {}, format="json")
def assertActionDestroy(self, pk, code: int = 200) -> t.Any: def assertActionDestroy(self, pk, code: int = 200) -> t.Optional[ReturnDict]:
""" """
Perform the ``destroy`` action, and assert that it will return a specific status code. Perform the ``destroy`` action, and assert that it will return a specific status code.
@ -166,250 +205,322 @@ class WriteSophonTestCase(ReadSophonTestCase, metaclass=abc.ABCMeta):
:param code: The expected status code. :param code: The expected status code.
:return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`. :return: The data the server responded with, or :data:`None` if the data evaluates to :data:`False`.
""" """
response = self.destroy(pk=pk) try:
self.assertEqual(response.status_code, code, msg=f"`destroy` did not return {code}") response = self.destroy(pk=pk)
return response.data except errors.HTTPException as exc:
self.assertEqual(exc.status, code, msg=f"`create` did not return {code}: {exc!r}")
return None
else:
self.assertEqual(response.status_code, code, msg=f"`destroy` did not return {code}: {response.data!r}")
return response.data
class ResearchGroupTests(WriteSophonTestCase): class UsersByIdTestCase(ReadSophonTestCase):
""" """
:class:`APITestCase` for the :class:`ResearchGroupViewSet`. Tests for :class:`sophon.core.views.UsersByIdViewSet`.
Since the viewset by itself is trivial, these tests are to verify that DRF is working as expected.
"""
@classmethod
def get_basename(cls) -> str:
return "user-by-id"
first_user: User = None
second_user: User = None
third_user: User = None
@classmethod
def setUpTestData(cls):
cls.first_user = User.objects.create_user(username="first", password="One")
cls.second_user = User.objects.create_user(username="second", password="Two")
cls.third_user = User.objects.create_user(username="third", password="Three")
def test_list_200(self):
data = self.assertActionList(200)
self.assertEqual(3, data["count"], msg="`list` did not return 3 users")
self.assertEqual(3, len(data["results"]), msg="`list` results did not match count")
self.assertData(data["results"][0], {"username": "first"})
self.assertData(data["results"][1], {"username": "second"})
self.assertData(data["results"][2], {"username": "third"})
def test_retrieve_200(self):
data = self.assertActionRetrieve(self.first_user.id)
self.assertData(data, {"username": "first"})
data = self.assertActionRetrieve(self.second_user.id)
self.assertData(data, {"username": "second"})
data = self.assertActionRetrieve(self.third_user.id)
self.assertData(data, {"username": "third"})
def test_retrieve_400(self):
self.assertActionRetrieve("qwerty", code=400)
self.assertActionRetrieve(1.0, code=400)
self.assertActionRetrieve("xyzzy", code=400)
def test_retrieve_404(self):
self.assertActionRetrieve(100, code=404)
self.assertActionRetrieve(-1, code=404)
self.assertActionRetrieve(999999, code=404)
class UsersByUsernameTestCase(ReadSophonTestCase):
"""
Tests for :class:`sophon.core.views.UsersByUsernameViewSet`.
Basically the same as the UsersByIdTestCase, except that it checks for alphabetical ordering.
"""
@classmethod
def get_basename(cls) -> str:
return "user-by-username"
first_user: User = None
second_user: User = None
third_user: User = None
@classmethod
def setUpTestData(cls):
cls.first_user = User.objects.create_user(username="zzzzzz", password="zzzzzz")
cls.second_user = User.objects.create_user(username="wwwwww", password="wwwwww")
cls.third_user = User.objects.create_user(username="aaaaaa", password="aaaaaa")
def test_list_200(self):
data = self.assertActionList(200)
self.assertEqual(3, data["count"], msg="`list` did not return 3 users")
self.assertEqual(3, len(data["results"]), msg="`list` results did not match count")
self.assertData(data["results"][0], {"username": "aaaaaa"})
self.assertData(data["results"][1], {"username": "wwwwww"})
self.assertData(data["results"][2], {"username": "zzzzzz"})
def test_retrieve_200(self):
data = self.assertActionRetrieve(self.first_user.username)
self.assertData(data, {"username": "zzzzzz"})
data = self.assertActionRetrieve(self.second_user.username)
self.assertData(data, {"username": "wwwwww"})
data = self.assertActionRetrieve(self.third_user.username)
self.assertData(data, {"username": "aaaaaa"})
def test_retrieve_400(self):
self.assertActionRetrieve(1, code=400)
self.assertActionRetrieve(-1, code=400)
self.assertActionRetrieve(1.0, code=400)
def test_retrieve_404(self):
self.assertActionRetrieve("sas", code=404)
self.assertActionRetrieve("sos", code=404)
self.assertActionRetrieve("sus", code=404)
class ResearchGroupTestCase(WriteSophonTestCase):
"""
Tests for :class:`sophon.core.views.UsersByUsernameViewSet`.
These tests verify that :class:`sophon.core.views.SophonGroupViewSet` is working as intended.
""" """
@classmethod @classmethod
def get_basename(cls) -> str: def get_basename(cls) -> str:
return "research-group" return "research-group"
test_user: User = None owner_user: User = None
other_user: User = None member_user: User = None
outside_user: User = None
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
cls.test_user = User.objects.create_user(username="TEST", password="TheGreatDjangoTest") cls.owner_user = User.objects.create_user(username="owner", password="owner")
cls.other_user = User.objects.create_user(username="TAST", password="TheGreatDjangoTast") cls.member_user = User.objects.create_user(username="member", password="member")
cls.outside_user = User.objects.create_user(username="outside", password="outside")
models.ResearchGroup.objects.create( alpha = models.ResearchGroup.objects.create(
slug="alpha", slug="alpha",
name="Alpha", name="Alpha",
description="First test group.", description="First test group.",
owner=cls.test_user, owner=cls.owner_user,
access="MANUAL", access="MANUAL",
) )
alpha.members.set([cls.member_user])
models.ResearchGroup.objects.create( beta = models.ResearchGroup.objects.create(
slug="beta", slug="beta",
name="Beta", name="Beta",
description="Second test group.", description="Second test group.",
owner=cls.test_user, owner=cls.owner_user,
access="OPEN", access="OPEN",
) )
beta.members.set([])
def test_list(self): def test_list_200(self):
r = self.list_unwrap() data = self.assertActionList()
self.assertEqual(2, data["count"])
count = r["count"] self.assertEqual(2, len(data["results"]))
self.assertEqual(count, 2) self.assertData(data["results"][0], {
"slug": "alpha",
list_page = r["results"] "name": "Alpha",
"description": "First test group.",
self.assertIn("slug", list_page[0]) "owner": self.owner_user.id,
self.assertIn("name", list_page[0]) "members": [self.member_user.id],
self.assertIn("description", list_page[0]) "access": "MANUAL",
self.assertIn("owner", list_page[0]) })
self.assertIn("members", list_page[0]) self.assertData(data["results"][1], {
self.assertIn("access", list_page[0]) "slug": "beta",
"name": "Beta",
def test_retrieve_valid(self): "description": "Second test group.",
retrieved = self.retrieve_unwrap("alpha") "owner": self.owner_user.id,
self.assertIn("slug", retrieved)
self.assertIn("name", retrieved)
self.assertIn("description", retrieved)
self.assertIn("owner", retrieved)
self.assertIn("members", retrieved)
self.assertIn("access", retrieved)
self.assertEqual(retrieved["slug"], "alpha")
self.assertEqual(retrieved["name"], "Alpha")
self.assertEqual(retrieved["description"], "First test group.")
self.assertEqual(retrieved["owner"], self.test_user.id)
self.assertEqual(retrieved["members"], [])
self.assertEqual(retrieved["access"], "MANUAL")
def test_retrieve_not_existing(self):
self.retrieve_fail("banana", 404)
def test_create_valid(self):
self.client.login(username="TEST", password="TheGreatDjangoTest")
created = self.create_unwrap({
"slug": "omega",
"name": "Omega",
"description": "Last test group.",
"members": [], "members": [],
"access": "OPEN", "access": "OPEN",
}) })
self.assertIn("slug", created)
self.assertIn("name", created)
self.assertIn("description", created)
self.assertIn("owner", created)
self.assertIn("members", created)
self.assertIn("access", created)
retrieved = self.retrieve_unwrap("omega") def test_retrieve_200(self):
data = self.assertActionRetrieve("alpha")
self.assertData(data, {
"slug": "alpha",
"name": "Alpha",
"description": "First test group.",
"owner": self.owner_user.id,
"members": [self.member_user.id],
"access": "MANUAL",
})
self.assertIn("slug", retrieved) data = self.assertActionRetrieve("beta")
self.assertIn("name", retrieved) self.assertData(data, {
self.assertIn("description", retrieved) "slug": "beta",
self.assertIn("owner", retrieved) "name": "Beta",
self.assertIn("members", retrieved) "description": "Second test group.",
self.assertIn("access", retrieved) "owner": self.owner_user.id,
self.assertEqual(retrieved["slug"], "omega")
self.assertEqual(retrieved["name"], "Omega")
self.assertEqual(retrieved["description"], "Last test group.")
self.assertEqual(retrieved["owner"], self.test_user.id)
self.assertEqual(retrieved["members"], [])
self.assertEqual(retrieved["access"], "OPEN")
def test_create_not_logged_in(self):
self.create_fail({
"slug": "fail",
"name": "Failure",
"description": "This creation should fail.",
"members": [], "members": [],
"access": "OPEN", "access": "OPEN",
})
def test_retrieve_404(self):
self.assertActionRetrieve("banana", 404)
self.assertActionRetrieve("tomato", 404)
self.assertActionRetrieve("potato", 404)
# Since these are path parameters, they are interpreted as strings
self.assertActionRetrieve(1, 404)
self.assertActionRetrieve(-1, 404)
self.assertActionRetrieve(1.0, 404)
def test_create_201(self):
with self.as_user(self.owner_user.username):
# Ensure the group doesn't already exist
self.assertActionRetrieve("gamma", 404)
# Create the group
created = self.assertActionCreate({
"slug": "gamma",
"name": "Gamma",
"description": "Third test group.",
"members": [self.member_user.id],
"access": "OPEN",
}, 201)
self.assertData(created, {
"slug": "gamma",
"name": "Gamma",
"description": "Third test group.",
"owner": self.owner_user.id,
"members": [self.member_user.id],
"access": "OPEN",
})
# Ensure the group now exists
retrieved = self.assertActionRetrieve("gamma")
self.assertData(retrieved, {
"slug": "gamma",
"name": "Gamma",
"description": "Third test group.",
"owner": self.owner_user.id,
"members": [self.member_user.id],
"access": "OPEN",
})
def test_create_400(self):
self.assertActionCreate({}, 400)
self.assertActionCreate({
"slug": 1,
"name": 213478,
"description": 384592,
"members": {
"why not": "a dict"
},
"access": "yes",
}, 400)
def test_create_401(self):
self.assertActionCreate({
"slug": "delta",
"name": "Delta",
"description": "Fourth test group.",
"members": [self.member_user.id],
"access": "OPEN",
}, 401) }, 401)
def test_create_invalid_schema(self): def test_update_200(self):
self.client.login(username="TEST", password="TheGreatDjangoTest") with self.as_user(self.owner_user.username):
updated = self.assertActionUpdate("beta", {
"slug": "beta",
"name": "Beta",
"description": "Second test group.",
"owner": self.owner_user.id,
"members": [self.member_user.id], # <-
"access": "OPEN",
})
self.assertData(updated, {
"slug": "beta",
"name": "Beta",
"description": "Second test group.",
"owner": self.owner_user.id,
"members": [self.member_user.id],
"access": "OPEN",
})
self.create_fail({ def test_update_400(self):
"potato": "sweet", with self.as_user(self.owner_user.username):
"access": "OPEN", self.assertActionUpdate("beta", {
}, 400) "members": {
"nobody expects": "the dict inquisition",
}
}, 400)
def test_update_valid(self): # Using AllowAny, update always succeeds, even if permissions are missing, but won't apply any changes due to the access serializer
self.client.login(username="TEST", password="TheGreatDjangoTest") def test_update_unauthenticated(self):
self.assertActionUpdate("beta", {
"members": [self.outside_user.id],
})
self.create_unwrap({ retrieved = self.assertActionRetrieve("beta")
"slug": "gamma", self.assertData(retrieved, {
"name": "Gamma", "slug": "beta",
"description": "A test group to update.", "name": "Beta",
"description": "Second test group.",
"owner": self.owner_user.id,
"members": [], "members": [],
"access": "OPEN", "access": "OPEN",
}) })
retrieved = self.retrieve_unwrap("gamma") # Using AllowAny, update always succeeds, even if permissions are missing, but won't apply any changes due to the access serializer
def test_update_forbidden(self):
with self.as_user(self.outside_user.username):
self.assertActionUpdate("beta", {
"name": "Bbbbbbbbb",
})
self.assertEqual(retrieved["slug"], "gamma") retrieved = self.assertActionRetrieve("beta")
self.assertEqual(retrieved["name"], "Gamma") self.assertData(retrieved, {
self.assertEqual(retrieved["description"], "A test group to update.") "slug": "beta",
self.assertEqual(retrieved["owner"], self.test_user.id) "name": "Beta",
self.assertEqual(retrieved["members"], []) "description": "Second test group.",
self.assertEqual(retrieved["access"], "OPEN") "owner": self.owner_user.id,
"members": [],
"access": "OPEN",
})
updated = self.update_unwrap("gamma", { def test_destroy_204(self):
"slug": "gamma", with self.as_user(self.owner_user.username):
"name": "Gamma", self.assertActionDestroy("beta", 204)
"description": "An updated test group.", self.assertActionRetrieve("beta", 404)
"members": [],
"access": "MANUAL",
})
self.assertIn("slug", updated) def test_destroy_401(self):
self.assertIn("name", updated) self.assertActionDestroy("alpha", 401)
self.assertIn("description", updated)
self.assertIn("owner", updated)
self.assertIn("members", updated)
self.assertIn("access", updated)
self.assertEqual(updated["slug"], "gamma") def test_destroy_403(self):
self.assertEqual(updated["name"], "Gamma") with self.as_user(self.outside_user.username):
self.assertEqual(updated["description"], "An updated test group.") self.assertActionDestroy("alpha", 403)
self.assertEqual(updated["owner"], self.test_user.id)
self.assertEqual(updated["members"], [])
self.assertEqual(updated["access"], "MANUAL")
retrieved2 = self.retrieve_unwrap("gamma")
self.assertEqual(retrieved2["slug"], "gamma")
self.assertEqual(retrieved2["name"], "Gamma")
self.assertEqual(retrieved2["description"], "An updated test group.")
self.assertEqual(retrieved2["owner"], self.test_user.id)
self.assertEqual(retrieved2["members"], [])
self.assertEqual(retrieved2["access"], "MANUAL")
def test_update_not_logged_in(self):
self.update_fail("alpha", {
"slug": "alpha",
"name": "AAAAA",
"description": "An hacker has updated the Alpha group without permissions!",
"members": [],
"access": "MANUAL",
}, 401)
def test_update_unauthorized(self):
self.client.login(username="TAST", password="TheGreatDjangoTast")
self.update_fail("alpha", {
"slug": "alpha",
"name": "AAAAA",
"description": "An hacker has updated the Alpha group without permissions!",
"members": [],
"access": "MANUAL",
}, 403)
def test_update_invalid_schema(self):
self.client.login(username="TEST", password="TheGreatDjangoTest")
self.update_fail("alpha", {
"hahaha": "soccer",
}, 400)
def test_destroy_valid(self):
self.client.login(username="TEST", password="TheGreatDjangoTest")
self.create_unwrap({
"slug": "boom",
"name": "Boom!!!",
"description": "A group that should explode.",
"members": [],
"access": "OPEN",
})
self.destroy_unwrap("boom")
self.retrieve_fail("boom", 404)
def test_destroy_not_logged_in(self):
self.client.login(username="TEST", password="TheGreatDjangoTest")
self.create_unwrap({
"slug": "boom",
"name": "Boom!!!",
"description": "A group that should explode.",
"members": [],
"access": "OPEN",
})
self.client.logout()
self.destroy_fail("boom", 401)
self.retrieve_unwrap("boom")
def test_destroy_unauthorized(self):
self.client.login(username="TEST", password="TheGreatDjangoTest")
self.create_unwrap({
"slug": "doom",
"name": "Doom!!!",
"description": "A group about a game.",
"members": [],
"access": "OPEN",
})
self.client.logout()
self.client.login(username="TAST", password="TheGreatDjangoTast")
self.destroy_fail("doom", 403)
self.retrieve_unwrap("doom")