{"record":{"id":"6b274fafc0f499f0","repo":"apache/beam","slug":"f-test-specification-identifier-must-have-at-least-one","errorCode":null,"errorMessage":"f'test specification {identifier} must have at least one expected_outputs or expected_inputs'","messagePattern":"f'test specification (.+?) must have at least one expected_outputs or expected_inputs'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/yaml/yaml_testing.py","lineNumber":155,"sourceCode":"  return spec\n\n\ndef validate_test_spec(test_spec):\n  if not isinstance(test_spec, dict):\n    raise TypeError(\n        f'Test specification must be an object, got {type(test_spec)}')\n  identifier = (\n      test_spec.get('name', 'unknown') +\n      f' at line {yaml_transform.SafeLineLoader.get_line(test_spec)}')\n\n  if not isinstance(test_spec.get('allowed_sources', []), list):\n    raise TypeError(\n        f'allowed_sources of test specification {identifier} '\n        f'must be a list, got {type(test_spec[\"allowed_sources\"])}')\n\n  if (not test_spec.get('expected_outputs', []) and\n      not test_spec.get('expected_inputs', [])):\n    raise ValueError(\n        f'test specification {identifier} '\n        f'must have at least one expected_outputs or expected_inputs')\n\n  unknown_attrs = set(\n      yaml_transform.SafeLineLoader.strip_metadata(test_spec).keys()) - set([\n          'name',\n          'mock_inputs',\n          'mock_outputs',\n          'expected_outputs',\n          'expected_inputs',\n          'allowed_sources',\n      ])\n  if unknown_attrs:\n    raise ValueError(\n        f'test specification {identifier} '\n        f'has unknown attributes {list(unknown_attrs)}')\n\n  for attr_type in ('mock_inputs',","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/yaml/yaml_testing.py#L137-L173","documentation":"A test specification must declare at least one expectation: either expected_outputs or expected_inputs. A test with neither would silently assert nothing, so validate_test_spec raises a ValueError identifying the test by name and line.","triggerScenarios":"A test entry that provides mocks or allowed_sources but omits both expected_outputs and expected_inputs (or provides them as empty values).","commonSituations":"Scaffolding a test and forgetting to fill in expectations, or deleting expected blocks during debugging and committing the empty test.","solutions":["Add expected_outputs mapping output names to expected record lists.","Add expected_inputs mapping input names to record lists if testing the input contract.","Remove the test entry if it asserts nothing."],"exampleFix":"# before\n- name: my_test\n  allowed_sources: [Create]\n\n# after\n- name: my_test\n  allowed_sources: [Create]\n  expected_outputs:\n    result: [{id: 1}]","handlingStrategy":"validation","validationCode":"if not test_spec.get('expected_outputs') and not test_spec.get('expected_inputs'):\n    raise ValueError(f\"test '{test_spec.get('name')}' needs expected_outputs or expected_inputs\")","typeGuard":"def test_has_expectations(spec: dict) -> bool:\n    return bool(spec.get('expected_outputs')) or bool(spec.get('expected_inputs'))","tryCatchPattern":"try:\n    validate_test_spec(test_spec)\nexcept ValueError as e:\n    logging.error('Incomplete test spec: %s', e)\n    raise","preventionTips":["Scaffold new tests with at least one expectation block","Never commit tests with expectations stripped for debugging","Require expected_outputs/expected_inputs in test templates"],"tags":["python","apache-beam","yaml","testing"],"backgroundTag":"missing-required-config-field","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}