afscgap.test.test_client

Unit tests for the logic that interacts with the API and makes HTTP requests.

(c) 2023 Regents of University of California / The Eric and Wendy Schmidt Center for Data Science and the Environment at UC Berkeley.

This file is part of afscgap released under the BSD 3-Clause License. See LICENSE.md.

  1"""
  2Unit tests for the logic that interacts with the API and makes HTTP requests.
  3
  4(c) 2023 Regents of University of California / The Eric and Wendy Schmidt Center
  5for Data Science and the Environment at UC Berkeley.
  6
  7This file is part of afscgap released under the BSD 3-Clause License. See
  8LICENSE.md.
  9"""
 10import json
 11import unittest
 12import unittest.mock
 13
 14import afscgap.client
 15import afscgap.test.test_tools
 16
 17# pylint: disable=C0115, C0116
 18
 19
 20class ClientTests(unittest.TestCase):
 21
 22    def setUp(self):
 23        self._result_1 = afscgap.test.test_tools.make_result_json(
 24            'result_1.json'
 25        )
 26        self._result_2 = afscgap.test.test_tools.make_result_json(
 27            'result_2.json'
 28        )
 29        self._mock_requsetor = unittest.mock.MagicMock(
 30            side_effect=[self._result_1, self._result_2]
 31        )
 32        self._cursor = afscgap.client.ApiServiceCursor(
 33            'BASE_URL',
 34            requestor=self._mock_requsetor
 35        )
 36        self._cursor_filter_incomplete = afscgap.client.ApiServiceCursor(
 37            'BASE_URL',
 38            requestor=self._mock_requsetor,
 39            filter_incomplete=True
 40        )
 41        self._cursor_override = afscgap.client.ApiServiceCursor(
 42            'BASE_URL',
 43            limit=12,
 44            start_offset=34,
 45            requestor=self._mock_requsetor
 46        )
 47
 48    def test_get_query_url(self):
 49        result = afscgap.client.get_query_url({
 50            'param1': None,
 51            'param2': 2,
 52            'param3': 'three'
 53        })
 54        self.assertTrue('noaa.gov' in result)
 55
 56        components = result.split('?q=')
 57        self.assertEqual(len(components), 2)
 58
 59        query = json.loads(components[1])
 60        self.assertFalse('param1' in query)
 61        self.assertEqual(query['param2'], 2)
 62        self.assertEqual(query['param3'], 'three')
 63
 64    def test_meta(self):
 65        self.assertEqual(self._cursor.get_base_url(), 'BASE_URL')
 66        self.assertIsNone(self._cursor.get_limit())
 67        self.assertIsNone(self._cursor.get_start_offset())
 68        self.assertEqual(self._cursor_override.get_limit(), 12)
 69        self.assertEqual(self._cursor_override.get_start_offset(), 34)
 70
 71    def test_get_page_url_default(self):
 72        self.assertEqual(self._cursor.get_page_url(), 'BASE_URL')
 73        self.assertEqual(
 74            self._cursor_override.get_page_url(),
 75            'BASE_URL&offset=34&limit=12'
 76        )
 77
 78    def test_get_page_url_override(self):
 79        self.assertEqual(
 80            self._cursor.get_page_url(limit=56, offset=78),
 81            'BASE_URL&offset=78&limit=56'
 82        )
 83
 84    def test_get_page(self):
 85        result = self._cursor.get_page()
 86        self.assertEqual(len(result), 10)
 87        self.assertEqual(result[0].get_srvy(), 'GOA')
 88
 89    def test_get_page_invalid(self):
 90        self._cursor.get_page()
 91        
 92        with self.assertRaises(RuntimeError):
 93            self._cursor.get_page()
 94
 95    def test_get_page_invalid_ignore(self):
 96        self._cursor.get_page(ignore_invalid=True)
 97        result = self._cursor.get_page(ignore_invalid=True)
 98        self.assertEqual(len(result), 10)
 99
100    def test_find_next_url_present(self):
101        loaded_data = afscgap.test.test_tools.load_test_data_json(
102            'result_1.json'
103        )
104        next_url = self._cursor._find_next_url(loaded_data)
105        self.assertEqual(
106            next_url,
107            'https://apps-st.fisheries.noaa.gov/ods/foss/afsc_groundfish_survey/?q=%7B%22year%22:2021%2C%22latitude_dd%22:%7B%22%24gt%22:56.99%2C%22%24lt%22:+57.04%7D%2C%22longitude_dd%22:%7B%22%24gt%22:-143.96%2C%22%24lt%22:-144.01%7D%7D&offset=10&limit=10'
108        )
109
110    def test_find_next_url_not_present(self):
111        loaded_data = afscgap.test.test_tools.load_test_data_json(
112            'result_2.json'
113        )
114        next_url = self._cursor._find_next_url(loaded_data)
115        self.assertIsNone(next_url)
116
117    def test_iterate(self):
118        result = list(self._cursor)
119        self.assertEqual(len(result), 20)
120        self.assertEqual(result[0].get_srvy(), 'GOA')
121
122    def test_iterate_incomplete(self):
123        result = list(self._cursor_filter_incomplete)
124        self.assertEqual(len(result), 19)
125        self.assertEqual(result[0].get_srvy(), 'GOA')
126
127    def test_to_dicts(self):
128        result = list(self._cursor.to_dicts())
129        self.assertEqual(len(result), 20)
130        self.assertEqual(result[0]['srvy'], 'GOA')
131
132    def test_to_dicts_incomplete(self):
133        result = list(self._cursor_filter_incomplete.to_dicts())
134        self.assertEqual(len(result), 19)
135        self.assertEqual(result[0]['srvy'], 'GOA')
136
137    def test_parse_record(self):
138        result = afscgap.test.test_tools.load_test_data_json('result_1.json')
139        parsed = afscgap.client.parse_record(result['items'][0])
140        self.assertEqual(parsed.get_srvy(), 'GOA')
141        self.assertAlmostEquals(parsed.get_vessel_id(), 148)
142        self.assertAlmostEquals(
143            parsed.get_cpue_weight(units='kg1000/km2'),
144            40.132273,
145            places=5
146        )
147
148    def test_to_dict(self):
149        result = afscgap.test.test_tools.load_test_data_json('result_1.json')
150        parsed = afscgap.client.parse_record(result['items'][0])
151        parsed_dict = parsed.to_dict()
152        self.assertEqual(parsed_dict['srvy'], 'GOA')
153
154    def test_try_parse_incomplete(self):
155        parsed = afscgap.client.try_parse({})
156        self.assertFalse(parsed.meets_requirements(True))
157        self.assertFalse(parsed.meets_requirements(False))
158        self.assertIsNone(parsed.get_parsed())
159
160    def test_try_parse_success(self):
161        result = afscgap.test.test_tools.load_test_data_json('result_1.json')
162        parsed = afscgap.client.try_parse(result['items'][0])
163        self.assertTrue(parsed.meets_requirements(True))
164        self.assertTrue(parsed.meets_requirements(False))
165        self.assertIsNotNone(parsed.get_parsed())
166
167    def test_try_parse_invalid(self):
168        result = afscgap.test.test_tools.load_test_data_json('result_1.json')
169        parsed = afscgap.client.try_parse(result['items'][9])
170        self.assertTrue(parsed.meets_requirements(True))
171        self.assertFalse(parsed.meets_requirements(False))
172        self.assertIsNotNone(parsed.get_parsed())
class ClientTests(unittest.case.TestCase):
 21class ClientTests(unittest.TestCase):
 22
 23    def setUp(self):
 24        self._result_1 = afscgap.test.test_tools.make_result_json(
 25            'result_1.json'
 26        )
 27        self._result_2 = afscgap.test.test_tools.make_result_json(
 28            'result_2.json'
 29        )
 30        self._mock_requsetor = unittest.mock.MagicMock(
 31            side_effect=[self._result_1, self._result_2]
 32        )
 33        self._cursor = afscgap.client.ApiServiceCursor(
 34            'BASE_URL',
 35            requestor=self._mock_requsetor
 36        )
 37        self._cursor_filter_incomplete = afscgap.client.ApiServiceCursor(
 38            'BASE_URL',
 39            requestor=self._mock_requsetor,
 40            filter_incomplete=True
 41        )
 42        self._cursor_override = afscgap.client.ApiServiceCursor(
 43            'BASE_URL',
 44            limit=12,
 45            start_offset=34,
 46            requestor=self._mock_requsetor
 47        )
 48
 49    def test_get_query_url(self):
 50        result = afscgap.client.get_query_url({
 51            'param1': None,
 52            'param2': 2,
 53            'param3': 'three'
 54        })
 55        self.assertTrue('noaa.gov' in result)
 56
 57        components = result.split('?q=')
 58        self.assertEqual(len(components), 2)
 59
 60        query = json.loads(components[1])
 61        self.assertFalse('param1' in query)
 62        self.assertEqual(query['param2'], 2)
 63        self.assertEqual(query['param3'], 'three')
 64
 65    def test_meta(self):
 66        self.assertEqual(self._cursor.get_base_url(), 'BASE_URL')
 67        self.assertIsNone(self._cursor.get_limit())
 68        self.assertIsNone(self._cursor.get_start_offset())
 69        self.assertEqual(self._cursor_override.get_limit(), 12)
 70        self.assertEqual(self._cursor_override.get_start_offset(), 34)
 71
 72    def test_get_page_url_default(self):
 73        self.assertEqual(self._cursor.get_page_url(), 'BASE_URL')
 74        self.assertEqual(
 75            self._cursor_override.get_page_url(),
 76            'BASE_URL&offset=34&limit=12'
 77        )
 78
 79    def test_get_page_url_override(self):
 80        self.assertEqual(
 81            self._cursor.get_page_url(limit=56, offset=78),
 82            'BASE_URL&offset=78&limit=56'
 83        )
 84
 85    def test_get_page(self):
 86        result = self._cursor.get_page()
 87        self.assertEqual(len(result), 10)
 88        self.assertEqual(result[0].get_srvy(), 'GOA')
 89
 90    def test_get_page_invalid(self):
 91        self._cursor.get_page()
 92        
 93        with self.assertRaises(RuntimeError):
 94            self._cursor.get_page()
 95
 96    def test_get_page_invalid_ignore(self):
 97        self._cursor.get_page(ignore_invalid=True)
 98        result = self._cursor.get_page(ignore_invalid=True)
 99        self.assertEqual(len(result), 10)
100
101    def test_find_next_url_present(self):
102        loaded_data = afscgap.test.test_tools.load_test_data_json(
103            'result_1.json'
104        )
105        next_url = self._cursor._find_next_url(loaded_data)
106        self.assertEqual(
107            next_url,
108            'https://apps-st.fisheries.noaa.gov/ods/foss/afsc_groundfish_survey/?q=%7B%22year%22:2021%2C%22latitude_dd%22:%7B%22%24gt%22:56.99%2C%22%24lt%22:+57.04%7D%2C%22longitude_dd%22:%7B%22%24gt%22:-143.96%2C%22%24lt%22:-144.01%7D%7D&offset=10&limit=10'
109        )
110
111    def test_find_next_url_not_present(self):
112        loaded_data = afscgap.test.test_tools.load_test_data_json(
113            'result_2.json'
114        )
115        next_url = self._cursor._find_next_url(loaded_data)
116        self.assertIsNone(next_url)
117
118    def test_iterate(self):
119        result = list(self._cursor)
120        self.assertEqual(len(result), 20)
121        self.assertEqual(result[0].get_srvy(), 'GOA')
122
123    def test_iterate_incomplete(self):
124        result = list(self._cursor_filter_incomplete)
125        self.assertEqual(len(result), 19)
126        self.assertEqual(result[0].get_srvy(), 'GOA')
127
128    def test_to_dicts(self):
129        result = list(self._cursor.to_dicts())
130        self.assertEqual(len(result), 20)
131        self.assertEqual(result[0]['srvy'], 'GOA')
132
133    def test_to_dicts_incomplete(self):
134        result = list(self._cursor_filter_incomplete.to_dicts())
135        self.assertEqual(len(result), 19)
136        self.assertEqual(result[0]['srvy'], 'GOA')
137
138    def test_parse_record(self):
139        result = afscgap.test.test_tools.load_test_data_json('result_1.json')
140        parsed = afscgap.client.parse_record(result['items'][0])
141        self.assertEqual(parsed.get_srvy(), 'GOA')
142        self.assertAlmostEquals(parsed.get_vessel_id(), 148)
143        self.assertAlmostEquals(
144            parsed.get_cpue_weight(units='kg1000/km2'),
145            40.132273,
146            places=5
147        )
148
149    def test_to_dict(self):
150        result = afscgap.test.test_tools.load_test_data_json('result_1.json')
151        parsed = afscgap.client.parse_record(result['items'][0])
152        parsed_dict = parsed.to_dict()
153        self.assertEqual(parsed_dict['srvy'], 'GOA')
154
155    def test_try_parse_incomplete(self):
156        parsed = afscgap.client.try_parse({})
157        self.assertFalse(parsed.meets_requirements(True))
158        self.assertFalse(parsed.meets_requirements(False))
159        self.assertIsNone(parsed.get_parsed())
160
161    def test_try_parse_success(self):
162        result = afscgap.test.test_tools.load_test_data_json('result_1.json')
163        parsed = afscgap.client.try_parse(result['items'][0])
164        self.assertTrue(parsed.meets_requirements(True))
165        self.assertTrue(parsed.meets_requirements(False))
166        self.assertIsNotNone(parsed.get_parsed())
167
168    def test_try_parse_invalid(self):
169        result = afscgap.test.test_tools.load_test_data_json('result_1.json')
170        parsed = afscgap.client.try_parse(result['items'][9])
171        self.assertTrue(parsed.meets_requirements(True))
172        self.assertFalse(parsed.meets_requirements(False))
173        self.assertIsNotNone(parsed.get_parsed())

A class whose instances are single test cases.

By default, the test code itself should be placed in a method named 'runTest'.

If the fixture may be used for many test cases, create as many test methods as are needed. When instantiating such a TestCase subclass, specify in the constructor arguments the name of the test method that the instance is to execute.

Test authors should subclass TestCase for their own tests. Construction and deconstruction of the test's environment ('fixture') can be implemented by overriding the 'setUp' and 'tearDown' methods respectively.

If it is necessary to override the __init__ method, the base class __init__ method must always be called. It is important that subclasses should not change the signature of their __init__ method, since instances of the classes are instantiated automatically by parts of the framework in order to be run.

When subclassing TestCase, you can set these attributes:

  • failureException: determines which exception will be raised when the instance's assertion methods fail; test methods raising this exception will be deemed to have 'failed' rather than 'errored'.
  • longMessage: determines whether long messages (including repr of objects used in assert methods) will be printed on failure in addition to any explicit message passed.
  • maxDiff: sets the maximum length of a diff in failure messages by assert methods using difflib. It is looked up as an instance attribute so can be configured by individual tests if required.
def setUp(self):
23    def setUp(self):
24        self._result_1 = afscgap.test.test_tools.make_result_json(
25            'result_1.json'
26        )
27        self._result_2 = afscgap.test.test_tools.make_result_json(
28            'result_2.json'
29        )
30        self._mock_requsetor = unittest.mock.MagicMock(
31            side_effect=[self._result_1, self._result_2]
32        )
33        self._cursor = afscgap.client.ApiServiceCursor(
34            'BASE_URL',
35            requestor=self._mock_requsetor
36        )
37        self._cursor_filter_incomplete = afscgap.client.ApiServiceCursor(
38            'BASE_URL',
39            requestor=self._mock_requsetor,
40            filter_incomplete=True
41        )
42        self._cursor_override = afscgap.client.ApiServiceCursor(
43            'BASE_URL',
44            limit=12,
45            start_offset=34,
46            requestor=self._mock_requsetor
47        )

Hook method for setting up the test fixture before exercising it.

def test_get_query_url(self):
49    def test_get_query_url(self):
50        result = afscgap.client.get_query_url({
51            'param1': None,
52            'param2': 2,
53            'param3': 'three'
54        })
55        self.assertTrue('noaa.gov' in result)
56
57        components = result.split('?q=')
58        self.assertEqual(len(components), 2)
59
60        query = json.loads(components[1])
61        self.assertFalse('param1' in query)
62        self.assertEqual(query['param2'], 2)
63        self.assertEqual(query['param3'], 'three')
def test_meta(self):
65    def test_meta(self):
66        self.assertEqual(self._cursor.get_base_url(), 'BASE_URL')
67        self.assertIsNone(self._cursor.get_limit())
68        self.assertIsNone(self._cursor.get_start_offset())
69        self.assertEqual(self._cursor_override.get_limit(), 12)
70        self.assertEqual(self._cursor_override.get_start_offset(), 34)
def test_get_page_url_default(self):
72    def test_get_page_url_default(self):
73        self.assertEqual(self._cursor.get_page_url(), 'BASE_URL')
74        self.assertEqual(
75            self._cursor_override.get_page_url(),
76            'BASE_URL&offset=34&limit=12'
77        )
def test_get_page_url_override(self):
79    def test_get_page_url_override(self):
80        self.assertEqual(
81            self._cursor.get_page_url(limit=56, offset=78),
82            'BASE_URL&offset=78&limit=56'
83        )
def test_get_page(self):
85    def test_get_page(self):
86        result = self._cursor.get_page()
87        self.assertEqual(len(result), 10)
88        self.assertEqual(result[0].get_srvy(), 'GOA')
def test_get_page_invalid(self):
90    def test_get_page_invalid(self):
91        self._cursor.get_page()
92        
93        with self.assertRaises(RuntimeError):
94            self._cursor.get_page()
def test_get_page_invalid_ignore(self):
96    def test_get_page_invalid_ignore(self):
97        self._cursor.get_page(ignore_invalid=True)
98        result = self._cursor.get_page(ignore_invalid=True)
99        self.assertEqual(len(result), 10)
def test_find_next_url_present(self):
101    def test_find_next_url_present(self):
102        loaded_data = afscgap.test.test_tools.load_test_data_json(
103            'result_1.json'
104        )
105        next_url = self._cursor._find_next_url(loaded_data)
106        self.assertEqual(
107            next_url,
108            'https://apps-st.fisheries.noaa.gov/ods/foss/afsc_groundfish_survey/?q=%7B%22year%22:2021%2C%22latitude_dd%22:%7B%22%24gt%22:56.99%2C%22%24lt%22:+57.04%7D%2C%22longitude_dd%22:%7B%22%24gt%22:-143.96%2C%22%24lt%22:-144.01%7D%7D&offset=10&limit=10'
109        )
def test_find_next_url_not_present(self):
111    def test_find_next_url_not_present(self):
112        loaded_data = afscgap.test.test_tools.load_test_data_json(
113            'result_2.json'
114        )
115        next_url = self._cursor._find_next_url(loaded_data)
116        self.assertIsNone(next_url)
def test_iterate(self):
118    def test_iterate(self):
119        result = list(self._cursor)
120        self.assertEqual(len(result), 20)
121        self.assertEqual(result[0].get_srvy(), 'GOA')
def test_iterate_incomplete(self):
123    def test_iterate_incomplete(self):
124        result = list(self._cursor_filter_incomplete)
125        self.assertEqual(len(result), 19)
126        self.assertEqual(result[0].get_srvy(), 'GOA')
def test_to_dicts(self):
128    def test_to_dicts(self):
129        result = list(self._cursor.to_dicts())
130        self.assertEqual(len(result), 20)
131        self.assertEqual(result[0]['srvy'], 'GOA')
def test_to_dicts_incomplete(self):
133    def test_to_dicts_incomplete(self):
134        result = list(self._cursor_filter_incomplete.to_dicts())
135        self.assertEqual(len(result), 19)
136        self.assertEqual(result[0]['srvy'], 'GOA')
def test_parse_record(self):
138    def test_parse_record(self):
139        result = afscgap.test.test_tools.load_test_data_json('result_1.json')
140        parsed = afscgap.client.parse_record(result['items'][0])
141        self.assertEqual(parsed.get_srvy(), 'GOA')
142        self.assertAlmostEquals(parsed.get_vessel_id(), 148)
143        self.assertAlmostEquals(
144            parsed.get_cpue_weight(units='kg1000/km2'),
145            40.132273,
146            places=5
147        )
def test_to_dict(self):
149    def test_to_dict(self):
150        result = afscgap.test.test_tools.load_test_data_json('result_1.json')
151        parsed = afscgap.client.parse_record(result['items'][0])
152        parsed_dict = parsed.to_dict()
153        self.assertEqual(parsed_dict['srvy'], 'GOA')
def test_try_parse_incomplete(self):
155    def test_try_parse_incomplete(self):
156        parsed = afscgap.client.try_parse({})
157        self.assertFalse(parsed.meets_requirements(True))
158        self.assertFalse(parsed.meets_requirements(False))
159        self.assertIsNone(parsed.get_parsed())
def test_try_parse_success(self):
161    def test_try_parse_success(self):
162        result = afscgap.test.test_tools.load_test_data_json('result_1.json')
163        parsed = afscgap.client.try_parse(result['items'][0])
164        self.assertTrue(parsed.meets_requirements(True))
165        self.assertTrue(parsed.meets_requirements(False))
166        self.assertIsNotNone(parsed.get_parsed())
def test_try_parse_invalid(self):
168    def test_try_parse_invalid(self):
169        result = afscgap.test.test_tools.load_test_data_json('result_1.json')
170        parsed = afscgap.client.try_parse(result['items'][9])
171        self.assertTrue(parsed.meets_requirements(True))
172        self.assertFalse(parsed.meets_requirements(False))
173        self.assertIsNotNone(parsed.get_parsed())
Inherited Members
unittest.case.TestCase
TestCase
failureException
longMessage
maxDiff
addTypeEqualityFunc
addCleanup
enterContext
addClassCleanup
enterClassContext
tearDown
setUpClass
tearDownClass
countTestCases
defaultTestResult
shortDescription
id
subTest
run
doCleanups
doClassCleanups
debug
skipTest
fail
assertFalse
assertTrue
assertRaises
assertWarns
assertLogs
assertNoLogs
assertEqual
assertNotEqual
assertAlmostEqual
assertNotAlmostEqual
assertSequenceEqual
assertListEqual
assertTupleEqual
assertSetEqual
assertIn
assertNotIn
assertIs
assertIsNot
assertDictEqual
assertDictContainsSubset
assertCountEqual
assertMultiLineEqual
assertLess
assertLessEqual
assertGreater
assertGreaterEqual
assertIsNone
assertIsNotNone
assertIsInstance
assertNotIsInstance
assertRaisesRegex
assertWarnsRegex
assertRegex
assertNotRegex
failUnlessRaises
failIf
assertRaisesRegexp
assertRegexpMatches
assertNotRegexpMatches
failUnlessEqual
assertEquals
failIfEqual
assertNotEquals
failUnlessAlmostEqual
assertAlmostEquals
failIfAlmostEqual
assertNotAlmostEquals
failUnless
assert_