Skip to content

Commit 1cc2beb

Browse files
committed
negative testing
1 parent 3e9052a commit 1cc2beb

8 files changed

+1862
-154
lines changed
12.4 KB
Binary file not shown.

expected_results.json renamed to expected_results/expected_results.json

+7
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@
1111
"expected": [
1212
{"study": "1368-0015", "site": "DEU1", "randomized_patients": 40, "trial_status": "recruitment"},
1313
{"study": "1368-0004", "site": "DEU2", "randomized_patients": 35, "trial_status": "ongoing"},
14+
{"study": "1368-0016", "site": "DEU3", "randomized_patients": 10, "trial_status": "completed"},
15+
{"study": "1368-0017", "site": "DEU4", "randomized_patients": 25, "trial_status": "on hold"},
1416
{"study": "1368-0018", "site": "DEU5", "randomized_patients": 50, "trial_status": "recruitment"}
1517
]
18+
},
19+
"active_patients_date": {
20+
"expected": [
21+
{"week": "2017-31", "active_patients": 30}
22+
]
1623
}
1724
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"active_patients_date_negative": {
3+
"expected": []
4+
}
5+
}

rules_config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ common_rules:
44
min: 0
55
trial_status:
66
type: string
7-
allowed: ["recruitment", "ongoing", "completed"]
7+
allowed: ["recruitment", "ongoing", "completed", "on hold"]
88
active_sites:
99
type: integer
1010
min: 0

tests/conftest.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,16 @@ def db_connection():
1313

1414
connection = engine.connect()
1515
yield connection
16-
connection.close()
16+
connection.close()
17+
18+
@pytest.fixture(scope='module')
19+
def db_connection_negative():
20+
engine = create_engine('sqlite:///:memory:')
21+
file_path = os.path.join(os.path.dirname(__file__), '..', 'data', 'validated_reference_dataset_errors.xlsx')
22+
df = pd.read_excel(file_path)
23+
df.to_sql('clinical_trials', engine, if_exists='replace', index=False)
24+
25+
connection = engine.connect()
26+
yield connection
27+
connection.close()
28+

tests/pytest_html_report.html

+1,695-148
Large diffs are not rendered by default.

tests/test_negative_sql_logic_yaml.py

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import sys
2+
import os
3+
import pytest
4+
import json
5+
import yaml
6+
7+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
8+
9+
from validation_rules_yaml import validate_entry, load_validation_rules
10+
11+
# @pytest.fixture(scope='module')
12+
# def expected_results():
13+
# return load_expected_results()
14+
@pytest.fixture(scope='module')
15+
def expected_results_negative():
16+
return load_expected_results_negative()
17+
18+
@pytest.fixture(scope='module')
19+
def validation_rules():
20+
return load_validation_rules()
21+
22+
def fetch_results_as_dict(results):
23+
return [dict(row) for row in results]
24+
25+
# def load_expected_results():
26+
# json_path = os.path.join(os.path.dirname(__file__), '..', 'expected_results/expected_results.json')
27+
# with open(json_path) as f:
28+
# return json.load(f)
29+
def load_expected_results_negative():
30+
json_path = os.path.join(os.path.dirname(__file__), '..', 'expected_results/expected_results_negative.json')
31+
with open(json_path) as f:
32+
return json.load(f)
33+
34+
def load_sql_query(file_name):
35+
sql_path = os.path.join(os.path.dirname(__file__), '..', 'sql_queries', file_name)
36+
with open(sql_path, 'r') as file:
37+
return file.read()
38+
39+
# # Positive Testing
40+
# def run_query_test(db_connection, expected_results, validation_rules, query_name, sql_file):
41+
# query_sql = load_sql_query(sql_file)
42+
# results = db_connection.execute(query_sql)
43+
# results_dict = fetch_results_as_dict(results)
44+
45+
# # Obtener las reglas específicas de la consulta
46+
# query_rules = validation_rules["queries"].get(query_name, {}).get("rules", {})
47+
48+
# # Combinar las reglas comunes con las reglas específicas de la consulta
49+
# combined_rules = {**validation_rules["common_rules"], **query_rules}
50+
51+
# # Filtrar resultados válidos
52+
# filtered_results = [result for result in results_dict if validate_entry(result, combined_rules)]
53+
54+
# # Convert lists to sets for comparison:
55+
# """
56+
# En lugar de hacer:
57+
# # Comparar con los resultados esperados: expected = expected_results[query_name]["expected"]
58+
# Mejor hacer:
59+
# Ignorar el orden de las filas y se enfoque en el contenido de los datos.
60+
# Convertir Diccionarios en Tuplas Ordenadas: tuple(sorted(d.items())) convierte cada diccionario
61+
# en una lista de pares clave-valor ordenados, luego en una tupla. Esto asegura que
62+
# cada diccionario tenga una representación única e independiente del orden de los campos.
63+
# Crear Conjuntos: set(...) convierte las listas de tuplas en conjuntos.
64+
# Esto permite que la comparación ignore el orden de las filas.
65+
# Comparación de Conjuntos: La comparación de los conjuntos filtered y expected asegura que ambos
66+
# contienen exactamente los mismos elementos, independientemente del orden en que aparecen.
67+
# """
68+
# expected = set(tuple(sorted(d.items())) for d in expected_results[query_name]["expected"])
69+
# filtered = set(tuple(sorted(d.items())) for d in filtered_results)
70+
71+
# assert filtered == expected, f"Error in {query_name}: {filtered} != {expected}"
72+
73+
# def test_active_sites_positive(db_connection, expected_results, validation_rules):
74+
# run_query_test(db_connection, expected_results, validation_rules, "active_sites_positive", "active_sites_positive.sql")
75+
76+
# def test_randomized_patients_positive(db_connection, expected_results, validation_rules):
77+
# run_query_test(db_connection, expected_results, validation_rules, "randomized_patients_positive", "randomized_patients_positive.sql")
78+
79+
# def test_active_patients_date(db_connection, expected_results, validation_rules):
80+
# run_query_test(db_connection, expected_results, validation_rules, "active_patients_date", "active_patients_date.sql")
81+
82+
# Negative Testing
83+
def run_query_test_negative(db_connection_negative, expected_results_negative, validation_rules, query_name, sql_file):
84+
query_sql = load_sql_query(sql_file)
85+
results = db_connection_negative.execute(query_sql)
86+
results_dict = fetch_results_as_dict(results)
87+
88+
# Obtener las reglas específicas de la consulta
89+
query_rules = validation_rules["queries"].get(query_name, {}).get("rules", {})
90+
91+
# Combinar las reglas comunes con las reglas específicas de la consulta
92+
combined_rules = {**validation_rules["common_rules"], **query_rules}
93+
94+
# Filtrar resultados válidos
95+
filtered_results = [result for result in results_dict if validate_entry(result, combined_rules)]
96+
97+
# Convert lists to sets for comparison:
98+
"""
99+
En lugar de hacer:
100+
# Comparar con los resultados esperados: expected = expected_results[query_name]["expected"]
101+
Mejor hacer:
102+
Ignorar el orden de las filas y se enfoque en el contenido de los datos.
103+
Convertir Diccionarios en Tuplas Ordenadas: tuple(sorted(d.items())) convierte cada diccionario
104+
en una lista de pares clave-valor ordenados, luego en una tupla. Esto asegura que
105+
cada diccionario tenga una representación única e independiente del orden de los campos.
106+
Crear Conjuntos: set(...) convierte las listas de tuplas en conjuntos.
107+
Esto permite que la comparación ignore el orden de las filas.
108+
Comparación de Conjuntos: La comparación de los conjuntos filtered y expected asegura que ambos
109+
contienen exactamente los mismos elementos, independientemente del orden en que aparecen.
110+
"""
111+
expected = set(tuple(sorted(d.items())) for d in expected_results_negative[query_name]["expected"])
112+
filtered = set(tuple(sorted(d.items())) for d in filtered_results)
113+
114+
assert filtered == expected, f"Error in {query_name}: {filtered} != {expected}"
115+
def test_active_patients_date_negative(db_connection_negative, expected_results_negative, validation_rules):
116+
run_query_test_negative(db_connection_negative, expected_results_negative, validation_rules, "active_patients_date_negative", "active_patients_date.sql")

tests/test_sql_logic_yaml.py

+25-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
def expected_results():
1313
return load_expected_results()
1414

15+
1516
@pytest.fixture(scope='module')
1617
def validation_rules():
1718
return load_validation_rules()
@@ -20,7 +21,7 @@ def fetch_results_as_dict(results):
2021
return [dict(row) for row in results]
2122

2223
def load_expected_results():
23-
json_path = os.path.join(os.path.dirname(__file__), '..', 'expected_results.json')
24+
json_path = os.path.join(os.path.dirname(__file__), '..', 'expected_results/expected_results.json')
2425
with open(json_path) as f:
2526
return json.load(f)
2627

@@ -29,6 +30,7 @@ def load_sql_query(file_name):
2930
with open(sql_path, 'r') as file:
3031
return file.read()
3132

33+
# Positive Testing
3234
def run_query_test(db_connection, expected_results, validation_rules, query_name, sql_file):
3335
query_sql = load_sql_query(sql_file)
3436
results = db_connection.execute(query_sql)
@@ -42,13 +44,32 @@ def run_query_test(db_connection, expected_results, validation_rules, query_name
4244

4345
# Filtrar resultados válidos
4446
filtered_results = [result for result in results_dict if validate_entry(result, combined_rules)]
47+
48+
# Convert lists to sets for comparison:
49+
"""
50+
En lugar de hacer:
51+
# Comparar con los resultados esperados: expected = expected_results[query_name]["expected"]
52+
Mejor hacer:
53+
Ignorar el orden de las filas y se enfoque en el contenido de los datos.
54+
Convertir Diccionarios en Tuplas Ordenadas: tuple(sorted(d.items())) convierte cada diccionario
55+
en una lista de pares clave-valor ordenados, luego en una tupla. Esto asegura que
56+
cada diccionario tenga una representación única e independiente del orden de los campos.
57+
Crear Conjuntos: set(...) convierte las listas de tuplas en conjuntos.
58+
Esto permite que la comparación ignore el orden de las filas.
59+
Comparación de Conjuntos: La comparación de los conjuntos filtered y expected asegura que ambos
60+
contienen exactamente los mismos elementos, independientemente del orden en que aparecen.
61+
"""
62+
expected = set(tuple(sorted(d.items())) for d in expected_results[query_name]["expected"])
63+
filtered = set(tuple(sorted(d.items())) for d in filtered_results)
4564

46-
# Comparar con los resultados esperados
47-
expected = expected_results[query_name]["expected"]
48-
assert filtered_results == expected, f"Error in {query_name}: {filtered_results} != {expected}"
65+
assert filtered == expected, f"Error in {query_name}: {filtered} != {expected}"
4966

5067
def test_active_sites_positive(db_connection, expected_results, validation_rules):
5168
run_query_test(db_connection, expected_results, validation_rules, "active_sites_positive", "active_sites_positive.sql")
5269

5370
def test_randomized_patients_positive(db_connection, expected_results, validation_rules):
5471
run_query_test(db_connection, expected_results, validation_rules, "randomized_patients_positive", "randomized_patients_positive.sql")
72+
73+
def test_active_patients_date(db_connection, expected_results, validation_rules):
74+
run_query_test(db_connection, expected_results, validation_rules, "active_patients_date", "active_patients_date.sql")
75+

0 commit comments

Comments
 (0)