Skip to content

Commit 60ba1ae

Browse files
authored
tests: Fix mypy errors and enable mypy in PR workflow (#201)
* tests: Fix mypy errors * PR workflow: Run mypy on examples and reformat step names * tests: Update test_service.py to use a fixture and type annotations * tests: Use object in type annotations instead of Any * tests: Rerun Black
1 parent 6bedfca commit 60ba1ae

5 files changed

Lines changed: 134 additions & 71 deletions

File tree

.github/workflows/PR.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,19 @@ jobs:
3333
run: poetry install -vvv
3434
- name: Lint the Code
3535
run: poetry run ni-python-styleguide lint
36-
- name: MyPy Static Analysis
36+
- name: Mypy static analysis (ni-measurementlink-service)
3737
run: poetry run mypy -p ni_measurementlink_service --show-error-codes -v
38-
- name: MyPy Static Analysis on examples
38+
- name: Mypy static analysis (examples)
3939
# `mypy -p examples` doesn't import _helpers.py correctly, so check one example directory at a time.
4040
run: |
4141
for example in examples/*/; do
4242
echo Analyzing $example
4343
poetry run mypy $example --show-error-codes -v
4444
done
45-
- name: MyPy Static Analysis ni_measurementlink_generator
45+
- name: Mypy static analysis (ni-measurementlink-generator)
4646
run: poetry run mypy -p ni_measurementlink_generator --show-error-codes -v
47+
- name: Mypy static analysis (tests)
48+
run: poetry run mypy tests --show-error-codes -v
4749

4850
checks-nimg:
4951
runs-on: ubuntu-latest

tests/acceptance/test_measurement_service.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@ def test___measurement_service___measure_with_large_array___returns_output(doubl
7777
assert measure_response.outputs.value == serialized_parameter
7878

7979

80-
def _host_service() -> int:
80+
def _host_service() -> str:
8181
measurement.sample_measurement_service.host_service()
82-
return str(measurement.sample_measurement_service.grpc_service.port)
82+
return measurement.sample_measurement_service.grpc_service.port
8383

8484

85-
def _create_channel(port):
85+
def _create_channel(port: str):
8686
return grpc.insecure_channel(
8787
"localhost:" + port,
8888
options=[

tests/integration/test_service_manager.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
"""Contains test to validate service_manager.py."""
2+
from typing import cast
3+
24
import grpc
35
import pytest
46
from examples.sample_measurement import measurement
57

68
from ni_measurementlink_service._internal.discovery_client import DiscoveryClient
79
from ni_measurementlink_service._internal.service_manager import GrpcService
10+
from ni_measurementlink_service._internal.stubs.ni.measurementlink.discovery.v1.discovery_service_pb2_grpc import (
11+
DiscoveryServiceStub,
12+
)
813
from ni_measurementlink_service._internal.stubs.ni.measurementlink.measurement.v1 import (
914
measurement_service_pb2,
1015
measurement_service_pb2_grpc,
1116
)
1217
from tests.utilities.fake_discovery_service import FakeDiscoveryServiceStub
13-
from tests.utilities.fake_discovery_service import FakeDiscoveryServiceStubError
1418

1519

16-
def test___grpc_service___start_service___service_hosted():
20+
def test___grpc_service___start_service___service_hosted(grpc_service: GrpcService):
1721
"""Test to validate if measurement service is started."""
18-
grpc_service = GrpcService(DiscoveryClient(FakeDiscoveryServiceStub()))
19-
2022
port_number = grpc_service.start(
2123
measurement.measurement_info,
2224
measurement.service_info,
@@ -28,10 +30,10 @@ def test___grpc_service___start_service___service_hosted():
2830
_validate_if_service_running_by_making_rpc(port_number)
2931

3032

31-
def test___grpc_service_without_discovery_service___start_service___service_hosted():
33+
def test___grpc_service_without_discovery_service___start_service___service_hosted(
34+
grpc_service: GrpcService,
35+
):
3236
"""Test to validate if measurement service start when the discovery service not available."""
33-
grpc_service = GrpcService(DiscoveryClient(FakeDiscoveryServiceStubError()))
34-
3537
port_number = grpc_service.start(
3638
measurement.measurement_info,
3739
measurement.service_info,
@@ -43,9 +45,8 @@ def test___grpc_service_without_discovery_service___start_service___service_host
4345
_validate_if_service_running_by_making_rpc(port_number)
4446

4547

46-
def test___grpc_service_started___stop_service___service_stopped():
48+
def test___grpc_service_started___stop_service___service_stopped(grpc_service: GrpcService):
4749
"""Test to validate if measurement service is stopped."""
48-
grpc_service = GrpcService(DiscoveryClient(FakeDiscoveryServiceStub()))
4950
port_number = grpc_service.start(
5051
measurement.measurement_info,
5152
measurement.service_info,
@@ -60,6 +61,24 @@ def test___grpc_service_started___stop_service___service_stopped():
6061
_validate_if_service_running_by_making_rpc(port_number)
6162

6263

64+
@pytest.fixture
65+
def grpc_service(discovery_client: DiscoveryClient) -> GrpcService:
66+
"""Create a GrpcService."""
67+
return GrpcService(discovery_client)
68+
69+
70+
@pytest.fixture
71+
def discovery_client(discovery_service_stub: FakeDiscoveryServiceStub) -> DiscoveryClient:
72+
"""Create a DiscoveryClient."""
73+
return DiscoveryClient(cast(DiscoveryServiceStub, discovery_service_stub))
74+
75+
76+
@pytest.fixture
77+
def discovery_service_stub() -> FakeDiscoveryServiceStub:
78+
"""Create a FakeDiscoveryServiceStub."""
79+
return FakeDiscoveryServiceStub()
80+
81+
6382
def _validate_if_service_running_by_making_rpc(port_number):
6483
"""Implicit validation of running service.
6584
Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
"""Contains tests to validate the discovery_client.py.
22
"""
3-
from ni_measurementlink_service._internal import discovery_client
3+
from typing import cast
4+
5+
import pytest
6+
7+
from ni_measurementlink_service._internal.discovery_client import (
8+
DiscoveryClient,
9+
_PROVIDED_MEASUREMENT_SERVICE,
10+
)
11+
from ni_measurementlink_service._internal.stubs.ni.measurementlink.discovery.v1.discovery_service_pb2_grpc import (
12+
DiscoveryServiceStub,
13+
)
414
from ni_measurementlink_service.measurement.info import ServiceInfo, MeasurementInfo
515
from tests.utilities.fake_discovery_service import (
616
FakeDiscoveryServiceStub,
7-
FakeDiscoveryServiceStubError,
817
)
918

1019

@@ -17,53 +26,63 @@
1726
)
1827

1928

20-
def test___discovery_service_available___register_service___registration_success():
29+
def test___discovery_service_available___register_service___registration_success(
30+
discovery_client: DiscoveryClient, discovery_service_stub: FakeDiscoveryServiceStub
31+
):
2132
"""Test the successful registration when the discovery service is available."""
22-
fake_discovery_service_stub = FakeDiscoveryServiceStub()
23-
discovery_client_obj = discovery_client.DiscoveryClient(fake_discovery_service_stub)
24-
25-
registration_success_flag = discovery_client_obj.register_measurement_service(
33+
registration_success_flag = discovery_client.register_measurement_service(
2634
_TEST_SERVICE_PORT, _TEST_SERVICE_INFO, _TEST_MEASUREMENT_INFO
2735
)
2836

29-
_validate_grpc_request(fake_discovery_service_stub.request)
37+
_validate_grpc_request(discovery_service_stub.request)
3038
assert registration_success_flag
3139

3240

33-
def test___discovery_service_available___unregister_registered_service___un_registration_success():
41+
def test___discovery_service_available___unregister_registered_service___unregistration_success(
42+
discovery_client: DiscoveryClient,
43+
):
3444
"""Test the successful un-registration of registered service."""
35-
fake_discovery_service_stub = FakeDiscoveryServiceStub()
36-
discovery_client_obj = discovery_client.DiscoveryClient(fake_discovery_service_stub)
37-
discovery_client_obj.register_measurement_service(
45+
discovery_client.register_measurement_service(
3846
_TEST_SERVICE_PORT, _TEST_SERVICE_INFO, _TEST_MEASUREMENT_INFO
3947
)
4048

41-
un_registration_success_flag = discovery_client_obj.unregister_service()
49+
unregistration_success_flag = discovery_client.unregister_service()
4250

43-
assert un_registration_success_flag
51+
assert unregistration_success_flag
4452

4553

46-
def test___discovery_service_available___unregister_non_registered_service___un_registration_failure():
54+
def test___discovery_service_available___unregister_non_registered_service___unregistration_failure(
55+
discovery_client: DiscoveryClient,
56+
):
4757
"""Test the unsuccessful un-registration of non-registered service."""
48-
fake_discovery_service_stub = FakeDiscoveryServiceStub()
49-
discovery_client_obj = discovery_client.DiscoveryClient(fake_discovery_service_stub)
50-
51-
un_registration_success_flag = discovery_client_obj.unregister_service()
58+
unregistration_success_flag = discovery_client.unregister_service()
5259

53-
assert ~un_registration_success_flag # False
60+
assert ~unregistration_success_flag # False
5461

5562

56-
def test___discovery_service_unavailable___register_service_registration_failure():
63+
def test___discovery_service_unavailable___register_service_registration_failure(
64+
discovery_client: DiscoveryClient,
65+
):
5766
"""Test the unsuccessful registration when discovery service is not available."""
58-
fake_discovery_service_stub = FakeDiscoveryServiceStubError()
59-
discovery_client_obj = discovery_client.DiscoveryClient(fake_discovery_service_stub)
60-
discovery_client_obj.register_measurement_service(
67+
discovery_client.register_measurement_service(
6168
_TEST_SERVICE_PORT, _TEST_SERVICE_INFO, _TEST_MEASUREMENT_INFO
6269
)
6370

64-
un_registration_success_flag = discovery_client_obj.unregister_service()
71+
unregistration_success_flag = discovery_client.unregister_service()
6572

66-
assert ~un_registration_success_flag # False
73+
assert ~unregistration_success_flag # False
74+
75+
76+
@pytest.fixture
77+
def discovery_client(discovery_service_stub: FakeDiscoveryServiceStub) -> DiscoveryClient:
78+
"""Create a DiscoveryClient."""
79+
return DiscoveryClient(cast(DiscoveryServiceStub, discovery_service_stub))
80+
81+
82+
@pytest.fixture
83+
def discovery_service_stub() -> FakeDiscoveryServiceStub:
84+
"""Create a FakeDiscoveryServiceStub."""
85+
return FakeDiscoveryServiceStub()
6786

6887

6988
def _validate_grpc_request(request):
@@ -72,7 +91,4 @@ def _validate_grpc_request(request):
7291
assert request.service_description.service_class == _TEST_SERVICE_INFO.service_class
7392
assert request.service_description.description_url == _TEST_SERVICE_INFO.description_url
7493
assert request.service_description.display_name == _TEST_MEASUREMENT_INFO.display_name
75-
assert (
76-
discovery_client._PROVIDED_MEASUREMENT_SERVICE
77-
in request.service_description.provided_interfaces
78-
)
94+
assert _PROVIDED_MEASUREMENT_SERVICE in request.service_description.provided_interfaces

tests/unit/test_service.py

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
11
"""Tests to validated user facing decorators in service.py."""
22
import pytest
33

4-
from ni_measurementlink_service.measurement.info import DataType
5-
from ni_measurementlink_service.measurement.info import TypeSpecialization
4+
from ni_measurementlink_service.measurement.info import (
5+
DataType,
6+
MeasurementInfo,
7+
ServiceInfo,
8+
TypeSpecialization,
9+
)
610
from ni_measurementlink_service.measurement.service import MeasurementService
711

812

9-
def test___measurement_service___register_measurement_method___method_registered():
10-
"""Test to validate register_measurement decorator."""
11-
measurement_service = MeasurementService(None, None)
13+
_TEST_SERVICE_INFO = ServiceInfo("TestServiceClass", "TestUrl")
14+
_TEST_MEASUREMENT_INFO = MeasurementInfo(
15+
display_name="TestMeasurement",
16+
version="1.0.0.0",
17+
ui_file_paths=[],
18+
)
1219

20+
21+
def test___measurement_service___register_measurement_method___method_registered(
22+
measurement_service: MeasurementService,
23+
):
24+
"""Test to validate register_measurement decorator."""
1325
measurement_service.register_measurement(_fake_measurement_function)
1426

1527
measurement_service.measure_function == _fake_measurement_function
@@ -31,12 +43,14 @@ def test___measurement_service___register_measurement_method___method_registered
3143
],
3244
)
3345
def test___measurement_service___add_configuration__configuration_added(
34-
display_name, type, default_value
46+
measurement_service: MeasurementService,
47+
display_name: str,
48+
type: DataType,
49+
default_value: object,
3550
):
3651
"""Test to validate the configuration decorator."""
37-
measurement_service = MeasurementService(None, None)
38-
3952
measurement_service.configuration(display_name, type, default_value)(_fake_measurement_function)
53+
4054
assert any(
4155
param.display_name == display_name
4256
and param.type == type.value[0]
@@ -54,11 +68,13 @@ def test___measurement_service___add_configuration__configuration_added(
5468
],
5569
)
5670
def test___measurement_service___add_pin_configuration__pin_configuration_added(
57-
display_name, type, default_value, instrument_type
71+
measurement_service: MeasurementService,
72+
display_name: str,
73+
type: DataType,
74+
default_value: object,
75+
instrument_type: str,
5876
):
5977
"""Test to validate the configuration decorator."""
60-
measurement_service = MeasurementService(None, None)
61-
6278
measurement_service.configuration(
6379
display_name, type, default_value, instrument_type=instrument_type
6480
)(_fake_measurement_function)
@@ -93,11 +109,12 @@ def test___measurement_service___add_pin_configuration__pin_configuration_added(
93109
],
94110
)
95111
def test___measurement_service___add_non_pin_configuration__pin_type_annotations_not_added(
96-
display_name, type, default_value
112+
measurement_service: MeasurementService,
113+
display_name: str,
114+
type: DataType,
115+
default_value: object,
97116
):
98117
"""Test to validate the configuration decorator."""
99-
measurement_service = MeasurementService(None, None)
100-
101118
measurement_service.configuration(display_name, type, default_value)(_fake_measurement_function)
102119

103120
assert not all(
@@ -114,11 +131,12 @@ def test___measurement_service___add_non_pin_configuration__pin_type_annotations
114131
],
115132
)
116133
def test___measurement_service___add_path_configuration__path_configuration_added(
117-
display_name, type, default_value
134+
measurement_service: MeasurementService,
135+
display_name: str,
136+
type: DataType,
137+
default_value: object,
118138
):
119139
"""Test to validate the configuration decorator."""
120-
measurement_service = MeasurementService(None, None)
121-
122140
measurement_service.configuration(display_name, type, default_value)(_fake_measurement_function)
123141

124142
assert any(
@@ -149,11 +167,12 @@ def test___measurement_service___add_path_configuration__path_configuration_adde
149167
],
150168
)
151169
def test___measurement_service___add_non_path_configuration__path_type_annotations_not_added(
152-
display_name, type, default_value
170+
measurement_service: MeasurementService,
171+
display_name: str,
172+
type: DataType,
173+
default_value: object,
153174
):
154175
"""Test to validate the configuration decorator."""
155-
measurement_service = MeasurementService(None, None)
156-
157176
measurement_service.configuration(display_name, type, default_value)(_fake_measurement_function)
158177

159178
assert not all(
@@ -181,11 +200,12 @@ def test___measurement_service___add_non_path_configuration__path_type_annotatio
181200
],
182201
)
183202
def test___measurement_service___add_configuration_with_mismatch_default_value__raises_type_error(
184-
display_name, type, default_value
203+
measurement_service: MeasurementService,
204+
display_name: str,
205+
type: DataType,
206+
default_value: object,
185207
):
186208
"""Test to validate the configuration decorator with default value mismatch."""
187-
measurement_service = MeasurementService(None, None)
188-
189209
with pytest.raises(TypeError):
190210
measurement_service.configuration(display_name, type, default_value)(
191211
_fake_measurement_function
@@ -207,10 +227,10 @@ def test___measurement_service___add_configuration_with_mismatch_default_value__
207227
("UInt44", DataType.UInt64),
208228
],
209229
)
210-
def test___measurement_service___add_output__output_added(display_name, type):
230+
def test___measurement_service___add_output__output_added(
231+
measurement_service: MeasurementService, display_name: str, type: DataType
232+
):
211233
"""Test to validate the output decorator."""
212-
measurement_service = MeasurementService(None, None)
213-
214234
measurement_service.output(display_name, type)(_fake_measurement_function)
215235

216236
assert any(
@@ -223,3 +243,9 @@ def test___measurement_service___add_output__output_added(display_name, type):
223243

224244
def _fake_measurement_function():
225245
pass
246+
247+
248+
@pytest.fixture
249+
def measurement_service() -> MeasurementService:
250+
"""Create a MeasurementService."""
251+
return MeasurementService(_TEST_MEASUREMENT_INFO, _TEST_SERVICE_INFO)

0 commit comments

Comments
 (0)