Skip to content

Commit 4bf908c

Browse files
authored
streamline test class (#109)
* added base test parent class for cleaner code * modified test_marsfiles and test_marsinterp to use base_test * modified tests for marscal marsformat marsplot * modified test_marsvars for base_test * adjusted short time lengths of dummy test files to work with test_marsfiles * cd to tests directory for actions
1 parent ae3c055 commit 4bf908c

12 files changed

+266
-484
lines changed

.github/workflows/marscalendar_test.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,6 @@ jobs:
4949
run: pip install -e .
5050
# Run the tests
5151
- name: Run MarsCalendar tests
52-
run: python -m unittest -v tests/test_marscalendar.py
52+
run: |
53+
cd tests
54+
python -m unittest -v test_marscalendar.py

.github/workflows/marsformat_test.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ jobs:
8282
# Run the integration tests with cleanup between tests
8383
- name: Run MarsFormat tests
8484
run: |
85-
python -m unittest -v tests/test_marsformat.py
85+
cd tests
86+
python -m unittest -v test_marsformat.py
8687
# Clean up temporary files to avoid disk space issues - OS specific
8788
- name: Clean up temp files (Unix)
8889
if: runner.os != 'Windows' && always()

.github/workflows/marsplot_test.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ jobs:
8282
# Run the integration tests with cleanup between tests
8383
- name: Run MarsPlot tests
8484
run: |
85-
python -m unittest -v tests/test_marsplot.py
85+
cd tests
86+
python -m unittest -v test_marsplot.py
8687
# Clean up temporary files to avoid disk space issues - OS specific
8788
- name: Clean up temp files (Unix)
8889
if: runner.os != 'Windows' && always()

.github/workflows/marspull_test.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,6 @@ jobs:
5353

5454
# Run the tests
5555
- name: Run MarsPull tests
56-
run: python -m unittest -v tests/test_marspull.py
56+
run: |
57+
cd tests
58+
python -m unittest -v test_marspull.py

tests/base_test.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Shared test class methods and functions
4+
"""
5+
6+
import os
7+
import sys
8+
import unittest
9+
import shutil
10+
import subprocess
11+
import tempfile
12+
import glob
13+
import numpy as np
14+
from netCDF4 import Dataset
15+
16+
class BaseTestCase(unittest.TestCase):
17+
"""Base class for integration tests with common setup methods"""
18+
19+
PREFIX = "Default_test_"
20+
FILESCRIPT = "create_ames_gcm_files.py"
21+
SHORTFILE = "short"
22+
23+
# Verify files were created
24+
expected_files = [
25+
'01336.atmos_average.nc',
26+
'01336.atmos_average_pstd_c48.nc',
27+
'01336.atmos_daily.nc',
28+
'01336.atmos_diurn.nc',
29+
'01336.atmos_diurn_pstd.nc',
30+
'01336.fixed.nc'
31+
]
32+
# Remove files created by the tests
33+
output_patterns = [
34+
]
35+
36+
@classmethod
37+
def setUpClass(cls):
38+
"""Set up the test environment"""
39+
# Create a temporary directory for the tests
40+
cls.test_dir = tempfile.mkdtemp(prefix=cls.PREFIX)
41+
print(f"Created temporary test directory: {cls.test_dir}")
42+
# Project root directory
43+
cls.project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
44+
print(f"Project root directory: {cls.project_root}")
45+
# Create test files
46+
cls.create_test_files()
47+
48+
@classmethod
49+
def create_test_files(cls):
50+
"""Create test netCDF files using create_ames_gcm_files.py"""
51+
# Get path to create_ames_gcm_files.py script
52+
create_files_script = os.path.join(cls.project_root, "tests", cls.FILESCRIPT)
53+
54+
# Execute the script to create test files - Important: pass the test_dir as argument
55+
cmd = [sys.executable, create_files_script, cls.test_dir, cls.SHORTFILE]
56+
57+
# Print the command being executed
58+
print(f"Creating test files with command: {' '.join(cmd)}")
59+
60+
try:
61+
result = subprocess.run(
62+
cmd,
63+
capture_output=True,
64+
text=True,
65+
cwd=cls.test_dir # Run in the test directory to ensure files are created there
66+
)
67+
68+
# Print output for debugging
69+
print(f"File creation STDOUT: {result.stdout}")
70+
print(f"File creation STDERR: {result.stderr}")
71+
72+
if result.returncode != 0:
73+
raise Exception(f"Failed to create test files: {result.stderr}")
74+
75+
except Exception as e:
76+
raise Exception(f"Error running create_ames_gcm_files.py: {e}")
77+
78+
# List files in the temp directory to debug
79+
print(f"Files in test directory after creation: {os.listdir(cls.test_dir)}")
80+
81+
for filename in cls.expected_files:
82+
filepath = os.path.join(cls.test_dir, filename)
83+
if not os.path.exists(filepath):
84+
raise Exception(f"Test file {filename} was not created in {cls.test_dir}")
85+
else:
86+
print(f"Confirmed test file exists: {filepath}")
87+
88+
def setUp(self):
89+
"""Change to temporary directory before each test"""
90+
os.chdir(self.test_dir)
91+
print(f"Changed to test directory: {os.getcwd()}")
92+
93+
def tearDown(self):
94+
"""Clean up after each test"""
95+
# Clean up any generated output files after each test but keep input files
96+
97+
for pattern in self.output_patterns:
98+
for file_path in glob.glob(os.path.join(self.test_dir, pattern)):
99+
try:
100+
os.remove(file_path)
101+
print(f"Removed file: {file_path}")
102+
except Exception as e:
103+
print(f"Warning: Could not remove file {file_path}: {e}")
104+
105+
# Return to test_dir
106+
os.chdir(self.test_dir)
107+
108+
@classmethod
109+
def tearDownClass(cls):
110+
"""Clean up the test environment"""
111+
try:
112+
# List files in temp directory before deleting to debug
113+
print(f"Files in test directory before cleanup: {os.listdir(cls.test_dir)}")
114+
shutil.rmtree(cls.test_dir, ignore_errors=True)
115+
print(f"Removed test directory: {cls.test_dir}")
116+
except Exception as e:
117+
print(f"Warning: Could not remove test directory {cls.test_dir}: {e}")
118+

tests/create_ames_gcm_files.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def create_mgcm_atmos_average(short=False):
169169

170170
# Shorten file length if wanted
171171
if short:
172-
len_time = 2
172+
len_time = 5
173173
else:
174174
len_time = 133
175175

@@ -287,16 +287,16 @@ def create_mgcm_atmos_average(short=False):
287287

288288
dst_num_micro_var = nc_file.createVariable('dst_num_micro', 'f4', ('time', 'pfull', 'lat', 'lon'))
289289
dst_num_micro_var.long_name = 'dust_number'
290-
dst_num_micro_var[:] = np.random.uniform(-3.8e-15, 6.3e+10, size=(133, 30, 48, 96))
290+
dst_num_micro_var[:] = np.random.uniform(-3.8e-15, 6.3e+10, size=(len_time, 30, 48, 96))
291291

292292
ice_mass_micro_var = nc_file.createVariable('ice_mass_micro', 'f4', ('time', 'pfull', 'lat', 'lon'))
293293
ice_mass_micro_var.long_name = 'ice_mass'
294-
ice_mass_micro_var[:] = np.random.uniform(-5.8e-34, 3.1e-03, size=(133, 30, 48, 96))
294+
ice_mass_micro_var[:] = np.random.uniform(-5.8e-34, 3.1e-03, size=(len_time, 30, 48, 96))
295295

296296
omega_var = nc_file.createVariable('omega', 'f4', ('time', 'pfull', 'lat', 'lon'))
297297
omega_var.long_name = 'vertical wind'
298298
omega_var.units = 'Pa/s'
299-
omega_var[:] = np.random.uniform(-0.045597, 0.0806756, size=(133, 30, 48, 96))
299+
omega_var[:] = np.random.uniform(-0.045597, 0.0806756, size=(len_time, 30, 48, 96))
300300

301301
ps_var = nc_file.createVariable('ps', 'f4', ('time', 'lat', 'lon'))
302302
ps_var.long_name = 'surface pressure'
@@ -342,7 +342,7 @@ def create_mgcm_atmos_daily(short=False):
342342

343343
# Shorten file length if wanted
344344
if short:
345-
len_time = 2
345+
len_time = 40
346346
else:
347347
len_time = 2672
348348

@@ -357,7 +357,10 @@ def create_mgcm_atmos_daily(short=False):
357357
time_var = nc_file.createVariable('time', 'f4', ('time',))
358358
time_var.long_name = 'time'
359359
time_var.units = 'days'
360-
time_var[:] = np.linspace(1336.2, 2004.0, len_time)
360+
if short:
361+
time_var[:] = np.linspace(1336.2, 1336.2+float(len_time)/4., len_time)
362+
else:
363+
time_var[:] = np.linspace(1336.2, 2004.0, len_time)
361364

362365
lat_var = nc_file.createVariable('lat', 'f4', ('lat',))
363366
lat_var.long_name = 'latitude'
@@ -405,8 +408,11 @@ def create_mgcm_atmos_daily(short=False):
405408
areo_var = nc_file.createVariable('areo', 'f4', ('time', 'scalar_axis'))
406409
areo_var.long_name = 'areo'
407410
areo_var.units = 'degrees'
408-
areo_vals = np.linspace(720.3, 1079.8, len_time)
409-
areo_data = np.zeros((len_time, 1)) # Create a 2D array with shape (133, 1)
411+
if short:
412+
areo_vals = np.linspace(720.3, 720.3+0.538*float(len_time)/4., len_time)
413+
else:
414+
areo_vals = np.linspace(720.3, 1079.8, len_time)
415+
areo_data = np.zeros((len_time, 1)) # Create a 2D array with shape (len_time, 1)
410416
for i in range(len_time):
411417
areo_data[i, 0] = areo_vals[i]
412418
areo_var[:] = areo_data
@@ -430,7 +436,7 @@ def create_mgcm_atmos_average_pstd(short=False):
430436

431437
# Shorten file length if wanted
432438
if short:
433-
len_time = 2
439+
len_time = 5
434440
else:
435441
len_time = 133
436442

@@ -508,22 +514,22 @@ def create_mgcm_atmos_average_pstd(short=False):
508514
theta_var = nc_file.createVariable('theta', 'f4', ('time', 'pstd', 'lat', 'lon'))
509515
theta_var.long_name = 'Potential temperature'
510516
theta_var.units = 'K'
511-
theta_var[:] = np.random.uniform(104.113, 3895.69, size=(133, 44, 48, 96))
517+
theta_var[:] = np.random.uniform(104.113, 3895.69, size=(len_time, 44, 48, 96))
512518

513519
rho_var = nc_file.createVariable('rho', 'f4', ('time', 'pstd', 'lat', 'lon'))
514520
rho_var.long_name = 'Density'
515521
rho_var.units = 'kg/m^3'
516-
rho_var[:] = np.random.uniform(7.05091e-07, 0.0668856, size=(133, 44, 48, 96))
522+
rho_var[:] = np.random.uniform(7.05091e-07, 0.0668856, size=(len_time, 44, 48, 96))
517523

518524
omega_var = nc_file.createVariable('omega', 'f4', ('time', 'pstd', 'lat', 'lon'))
519525
omega_var.long_name = 'vertical wind'
520526
omega_var.units = 'Pa/s'
521-
omega_var[:] = np.random.uniform(-0.045597, 0.0806756, size=(133, 44, 48, 96))
527+
omega_var[:] = np.random.uniform(-0.045597, 0.0806756, size=(len_time, 44, 48, 96))
522528

523529
w_var = nc_file.createVariable('w', 'f4', ('time', 'pstd', 'lat', 'lon'))
524530
w_var.long_name = 'w'
525531
w_var.units = 'm/s'
526-
w_var[:] = np.random.uniform(-2.02603, 1.58804, size=(133, 44, 48, 96))
532+
w_var[:] = np.random.uniform(-2.02603, 1.58804, size=(len_time, 44, 48, 96))
527533

528534
ps_var = nc_file.createVariable('ps', 'f4', ('time', 'lat', 'lon'))
529535
ps_var.long_name = 'surface pressure'
@@ -569,7 +575,7 @@ def create_mgcm_atmos_diurn_pstd(short=False):
569575

570576
# Shorten file length if wanted
571577
if short:
572-
len_time = 2
578+
len_time = 5
573579
else:
574580
len_time = 133
575581

@@ -662,7 +668,7 @@ def create_mgcm_atmos_diurn(short=False):
662668

663669
# Shorten file length if wanted
664670
if short:
665-
len_time = 2
671+
len_time = 5
666672
else:
667673
len_time = 133
668674

@@ -773,7 +779,7 @@ def create_mgcm_atmos_average_pstd_c48(short=False):
773779

774780
# Shorten file length if wanted
775781
if short:
776-
len_time = 2
782+
len_time = 5
777783
else:
778784
len_time = 133
779785

tests/test_marscalendar.py

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,14 @@
1414
import argparse
1515
import subprocess
1616
import re
17+
from base_test import BaseTestCase
1718

18-
class TestMarsCalendar(unittest.TestCase):
19+
class TestMarsCalendar(BaseTestCase):
1920
"""Integration test suite for MarsCalendar"""
20-
21-
@classmethod
22-
def setUpClass(cls):
23-
"""Set up the test environment"""
24-
# Create a temporary directory in the user's home directory
25-
cls.test_dir = os.path.join(os.path.expanduser('~'), 'MarsCalendar_test')
26-
os.makedirs(cls.test_dir, exist_ok=True)
27-
28-
# Project root directory
29-
cls.project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
30-
31-
def setUp(self):
32-
"""Change to temporary directory before each test"""
33-
os.chdir(self.test_dir)
34-
35-
@classmethod
36-
def tearDownClass(cls):
37-
"""Clean up the test environment"""
38-
try:
39-
shutil.rmtree(cls.test_dir, ignore_errors=True)
40-
except Exception:
41-
print(f"Warning: Could not remove test directory {cls.test_dir}")
21+
22+
PREFIX = "MarsCalendar_test_"
23+
FILESCRIPT = "create_ames_gcm_files.py"
24+
SHORTFILE = "short"
4225

4326
def run_mars_calendar(self, args):
4427
"""

0 commit comments

Comments
 (0)