class DescibeCursorPaginationView( APIViewTest, UsesGetMethod, ReturnsCursorPagination, ): url = lambda_fixture(lambda: url_for('pagination-cursor'))
class DescibeLimitOffsetPaginationView( APIViewTest, UsesGetMethod, ReturnsLimitOffsetPagination, ): url = lambda_fixture(lambda: url_for('pagination-limit-offset'))
class DescibePageNumberPaginationView( APIViewTest, UsesGetMethod, ReturnsPageNumberPagination, ): url = lambda_fixture(lambda: url_for('pagination-page-number'))
class DescribeLoginRequired( APIViewTest, UsesGetMethod, ForbidsAnonymousUsers, AsUser('user'), Returns200, ): # NOTE: this view simply returns 200, but requires an authenticated user # (i.e. it declares IsAuthenticated for its permission_classes) url = lambda_fixture(lambda: url_for('authorization-login-required'))
class DescribeData( APIViewTest, UsesPostMethod, ): # NOTE: this view simply returns the request's POST data as the response url = lambda_fixture(lambda: url_for('views-data')) # This fixture supports passing POST data in the request data = static_fixture({ 'post': 'malone', 'fizzbuzz': 'zibbzuff', }) def it_posts_data(self, json, data): expected = data actual = json assert expected == actual
class DescribeHeaders( APIViewTest, UsesGetMethod, ): # NOTE: this view simply returns the request's headers as the response url = lambda_fixture(lambda: url_for('views-headers')) # This fixture supports passing headers (e.g. `Authorization: Api-Key 123`) in the request headers = static_fixture({ 'Custom-Header': 'abc', 'Head': 'Shoulders, Knees, Toes', }) def it_passes_headers(self, json, headers): expected = headers actual = json assert_dict_is_subset(expected, actual)
class DescribeQueryParams( APIViewTest, UsesGetMethod, ): # NOTE: this view simply returns the request's query params as the response url = lambda_fixture(lambda: url_for('views-query-params')) # This fixture supports passing query params (e.g. ?key=val) with the requested URL query_params = static_fixture({ 'key': 'val', 'param': 'value', 'pink': 'floyd', }) def it_passes_query_params(self, json, query_params): expected = query_params actual = json assert expected == actual
class DescribeUserInfo( APIViewTest, UsesGetMethod, ): # NOTE: this view returns the username, first_name, last_name, and email of # the authenticated user. url = lambda_fixture(lambda: url_for('authentication-user-info')) class CaseAlice(AsUser('alice')): def it_returns_alices_info(self, alice, json): expected = { 'username': alice.username, 'first_name': alice.first_name, 'last_name': alice.last_name, 'email': alice.email, } actual = json assert expected == actual class CaseBob(AsUser('bob')): def it_returns_bobs_info(self, bob, json): expected = { 'username': bob.username, 'first_name': bob.first_name, 'last_name': bob.last_name, 'email': bob.email, } actual = json assert expected == actual class CaseAnonymous: def it_returns_no_info(self, json): # NOTE: AnonymousUser does not define first_name, last_name, or email. expected = {'username': ''} actual = json assert expected == actual
class DescribeMovieViewSet(ViewSetTest): list_url = lambda_fixture(lambda: url_for('movies-list')) detail_url = lambda_fixture( lambda movie: url_for('movies-detail', pk=movie.pk)) class DescribeList( UsesGetMethod, UsesListEndpoint, Returns200, ReturnsPageNumberPagination, ): movies = lambda_fixture( lambda: Movie.objects.bulk_create([ Movie(title="Alfred Hitchcock's The Byrds: A Biopic", year=1975), Movie(title='Forty-Two Monkeys', year=1997), ]), autouse=True, ) def it_returns_movies(self, movies, results): expected = express_movies(movies) actual = results assert expected == actual class ContextSearch( Returns200, ): matching_movies = lambda_fixture( lambda: Movie.objects.bulk_create([ Movie(title='Forty-Two Monkeys', year=1997), ])) non_matching_movies = lambda_fixture( lambda: Movie.objects.bulk_create([ Movie(title="Alfred Hitchcock's The Byrds: A Biopic", year=1975), ])) movies = lambda_fixture( lambda matching_movies, non_matching_movies: (matching_movies + non_matching_movies), autouse=True, ) query_params = static_fixture({ 'q': 'monkey', }) def it_returns_only_matching_movies(self, matching_movies, results): expected = express_movies(matching_movies) actual = results assert expected == actual class DescribeRetrieve( UsesGetMethod, UsesDetailEndpoint, Returns200, ): movie = lambda_fixture(lambda: Movie.objects.create( title='The Muffin Man', year=2038, )) def it_returns_movie(self, movie, json): expected = express_movie(movie) actual = json assert expected == actual
class DescribeKeyValueViewSet(ViewSetTest): list_url = lambda_fixture(lambda: url_for('views-key-values-list')) detail_url = lambda_fixture( lambda key_value: url_for('views-key-values-detail', pk=key_value.pk)) class DescribeList( UsesGetMethod, UsesListEndpoint, Returns200, ): # Here, we create some rows in the DB to play with. We set autouse=True, # so the fixture is evaluated even though nothing explicitly requests it. # The @pytest.mark.late (from pytest-fixture-order) mark ensures our # http request is run *after* all autouse fixtures. key_values = lambda_fixture( lambda: (KeyValue.objects.create_batch( alpha='beta', delta='gamma', )), autouse=True, ) def it_returns_key_values_rows(self, key_values, results): expected = express_key_values(key_values) actual = results assert expected == actual class DescribeCreate( UsesPostMethod, UsesListEndpoint, Returns201, ): data = static_fixture({ 'key': 'apple', 'value': 'π', }) ### # precondition_fixture uses the pytest dependency graph to ensure that, # if requested, this fixture is *always* evaluated before our HTTP request # is made. # # Here, we record the existing KeyValue IDs, so we can verify that a # new row was indeed created by our endpoint. # initial_key_value_ids = precondition_fixture( lambda: set(KeyValue.objects.values_list('pk', flat=True))) def it_creates_key_value(self, initial_key_value_ids, json): expected = initial_key_value_ids | {json['id']} actual = set(KeyValue.objects.values_list('pk', flat=True)) assert expected == actual def it_returns_key_value(self, json): key_value = KeyValue.objects.get(pk=json['id']) expected = express_key_value(key_value) actual = json assert expected == actual def it_sets_model_fields(self, data, json): key_value = KeyValue.objects.get(pk=json['id']) expected = data assert_model_attrs(key_value, expected) class DescribeRetrieve( UsesGetMethod, UsesDetailEndpoint, Returns200, ): # NOTE: autouse=True is not used, because the detail_url requests this # fixture key_value = lambda_fixture(lambda: KeyValue.objects.create( key='apple', value='π', )) def it_returns_key_value(self, key_value, json): expected = express_key_value(key_value) actual = json assert expected == actual class DescribeUpdate( UsesPatchMethod, UsesDetailEndpoint, Returns200, ): # NOTE: autouse=True is not used, because the detail_url requests this # fixture key_value = lambda_fixture(lambda: KeyValue.objects.create( key='apple', value='π', )) data = static_fixture({ 'key': 'banana', 'value': 'ρ', }) ### # precondition_fixture uses the pytest dependency graph to ensure that, # if requested, this fixture is *always* evaluated before our HTTP request # is made. # # Here, we record the existing KeyValue IDs, so we can verify that no # new rows are created by our endpoint. We request the `key_value` fixture, # to ensure it's included in this set. # initial_key_value_ids = precondition_fixture(lambda key_value: set( KeyValue.objects.values_list('pk', flat=True))) def it_updates_key_value(self, key_value, data): # After updating, refreshing our DB row is vital — otherwise, it # will appear as though our endpoint is not doing its job. key_value.refresh_from_db() expected = data assert_model_attrs(key_value, expected) def it_returns_key_value(self, key_value, json): # After updating, refreshing our DB row is vital — otherwise, it # will appear as though our endpoint is not doing its job. key_value.refresh_from_db() expected = express_key_value(key_value) actual = json assert expected == actual def it_doesnt_create_or_destroy_rows(self, initial_key_value_ids): expected = initial_key_value_ids actual = set(KeyValue.objects.values_list('pk', flat=True)) assert expected == actual class DescribeDestroy( UsesDeleteMethod, UsesDetailEndpoint, Returns204, ): # NOTE: autouse=True is not used, because the detail_url requests this # fixture key_value = lambda_fixture(lambda: KeyValue.objects.create( key='apple', value='π', )) ### # precondition_fixture uses the pytest dependency graph to ensure that, # if requested, this fixture is *always* evaluated before our HTTP request # is made. # # Here, we record the existing KeyValue IDs, so we can verify that our # endpoint actually deletes the row # initial_key_value_ids = precondition_fixture( lambda: set(KeyValue.objects.values_list('pk', flat=True))) def it_deletes_key_value(self, key_value, initial_key_value_ids): expected = initial_key_value_ids - {key_value.id} actual = set(KeyValue.objects.values_list('pk', flat=True)) assert expected == actual
class DescribeStatusCode( APIViewTest, UsesGetMethod, ): # Status code to be returned from view. # This will be overridden in child test contexts. status_code = not_implemented_fixture() url = lambda_fixture( lambda status_code: url_for('status-code', code=status_code)) class Case200(Returns200): status_code = static_fixture(200) class Case201(Returns201): status_code = static_fixture(201) class Case202(Returns202): status_code = static_fixture(202) class Case204(Returns204): status_code = static_fixture(204) class Case301(Returns301): status_code = static_fixture(301) class Case302(Returns302): status_code = static_fixture(302) class Case304(Returns304): status_code = static_fixture(304) class Case307(Returns307): status_code = static_fixture(307) class Case308(Returns308): status_code = static_fixture(308) class Case400(Returns400): status_code = static_fixture(400) class Case401(Returns401): status_code = static_fixture(401) class Case403(Returns403): status_code = static_fixture(403) class Case404(Returns404): status_code = static_fixture(404) class Case405(Returns405): status_code = static_fixture(405) class Case409(Returns409): status_code = static_fixture(409) class Case422(Returns422): status_code = static_fixture(422) class Case429(Returns429): status_code = static_fixture(429) class Case500(Returns500): status_code = static_fixture(500) class Case503(Returns503): status_code = static_fixture(503) class Case504(Returns504): status_code = static_fixture(504) class CaseArbitrary(ReturnsStatus(599)): status_code = static_fixture(599)