From 68b49c750ffd44bcfa110b842b14996cd0da9c29 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 15 Jan 2026 17:06:30 +0100 Subject: [PATCH 1/3] Added assertion statements, unit tests, and integration tests --- diffusion2d.py | 4 +- tests/integration/test_diffusion2d.py | 43 ++++++++++++++++-- tests/unit/test_diffusion2d_functions.py | 58 +++++++++++++++++++++--- 3 files changed, 94 insertions(+), 11 deletions(-) diff --git a/diffusion2d.py b/diffusion2d.py index 51a07f2..7d6ff53 100644 --- a/diffusion2d.py +++ b/diffusion2d.py @@ -38,6 +38,7 @@ def __init__(self): self.dt = None def initialize_domain(self, w=10., h=10., dx=0.1, dy=0.1): + assert type(w) is float and type(h) is float and type(dx) is float and type(dy) is float self.w = w self.h = h self.dx = dx @@ -45,7 +46,8 @@ def initialize_domain(self, w=10., h=10., dx=0.1, dy=0.1): self.nx = int(w / dx) self.ny = int(h / dy) - def initialize_physical_parameters(self, d=4., T_cold=300, T_hot=700): + def initialize_physical_parameters(self, d=4., T_cold=300., T_hot=700.): + assert type(d) is float and type(T_cold) is float and type(T_hot) is float self.D = d self.T_cold = T_cold self.T_hot = T_hot diff --git a/tests/integration/test_diffusion2d.py b/tests/integration/test_diffusion2d.py index fd026b4..22e95e3 100644 --- a/tests/integration/test_diffusion2d.py +++ b/tests/integration/test_diffusion2d.py @@ -3,17 +3,52 @@ """ from diffusion2d import SolveDiffusion2D +import pytest -def test_initialize_physical_parameters(): +@pytest.fixture +def solver(): + solver = SolveDiffusion2D() + return solver + + +def test_initialize_physical_parameters(solver): """ Checks function SolveDiffusion2D.initialize_domain """ - solver = SolveDiffusion2D() + input_w = 100. + input_h = 200. + input_dx = 0.1 + input_dy = 0.1 + + expected_T_cold = 100. + expected_T_hot = 1000. + expected_D = 5. + + expected_dt = 5 * 10e-5 + solver.initialize_domain(input_w, input_h, input_dx, input_dy) + solver.initialize_physical_parameters(expected_D, expected_T_cold, expected_T_hot) -def test_set_initial_condition(): + assert solver.dt == pytest.approx(expected_dt, rel=1e-12, abs=0.0) + + +def test_set_initial_condition(solver): """ Checks function SolveDiffusion2D.get_initial_function """ - solver = SolveDiffusion2D() + expected_nx = 50 + expected_ny = 100 + + input_w = 100. + input_h = 200. + input_dx = 0.1 + input_dy = 0.1 + + expected_T_cold = 100. + expected_T_hot = 1000. + expected_D = 5. + + solver.initialize_domain(input_w, input_h, input_dx, input_dy) + solver.initialize_physical_parameters(expected_D, expected_T_cold, expected_T_hot) + diff --git a/tests/unit/test_diffusion2d_functions.py b/tests/unit/test_diffusion2d_functions.py index c4277ff..fbb481a 100644 --- a/tests/unit/test_diffusion2d_functions.py +++ b/tests/unit/test_diffusion2d_functions.py @@ -3,24 +3,70 @@ """ from diffusion2d import SolveDiffusion2D +import pytest +import numpy as np -def test_initialize_domain(): +@pytest.fixture +def solver(): + solver = SolveDiffusion2D() + return solver + +def test_initialize_domain(solver: SolveDiffusion2D): """ Check function SolveDiffusion2D.initialize_domain """ - solver = SolveDiffusion2D() + expected_nx = 50 + expected_ny = 100 + input_w = 100. + input_h = 200. + input_dx = 2. + input_dy = 2. + + solver.initialize_domain(input_w, input_h, input_dx, input_dy) + assert solver.nx == expected_nx and solver.ny == expected_ny + -def test_initialize_physical_parameters(): +def test_initialize_physical_parameters(solver: SolveDiffusion2D): """ Checks function SolveDiffusion2D.initialize_domain """ - solver = SolveDiffusion2D() + expected_T_cold = 100. + expected_T_hot = 1000. + expected_D = 5. + + expected_dt = 5 * 10e-5 + + solver.dx = 0.1 + solver.dy = 0.1 + solver.initialize_physical_parameters(expected_D, expected_T_cold, expected_T_hot) -def test_set_initial_condition(): + assert solver.T_cold == expected_T_cold and solver.T_hot == expected_T_hot and \ + solver.D == expected_D and solver.dt == pytest.approx(expected_dt, rel=1e-12, abs=0.0) + + +def test_set_initial_condition(solver: SolveDiffusion2D): """ Checks function SolveDiffusion2D.get_initial_function """ - solver = SolveDiffusion2D() + solver.nx = 200 + solver.ny = 200 + solver.dx = 0.1 + solver.dy = 0.1 + solver.T_cold = 50 + solver.T_hot = 200 + + expected_u = solver.T_cold * np.ones((solver.nx, solver.ny)) + + r, cx, cy = 2, 5, 5 + r2 = r ** 2 + for i in range(solver.nx): + for j in range(solver.ny): + p2 = (i * solver.dx - cx) ** 2 + (j * solver.dy - cy) ** 2 + if p2 < r2: + expected_u[i, j] = solver.T_hot + + calculated_u = solver.set_initial_condition() + assert np.array_equal(expected_u, calculated_u) From 502df7e91df64259e3c6636ff7cac02b99146986 Mon Sep 17 00:00:00 2001 From: Marcel Graf Date: Thu, 15 Jan 2026 17:43:46 +0100 Subject: [PATCH 2/3] Completed second integration test --- tests/integration/test_diffusion2d.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/integration/test_diffusion2d.py b/tests/integration/test_diffusion2d.py index 22e95e3..d2d875c 100644 --- a/tests/integration/test_diffusion2d.py +++ b/tests/integration/test_diffusion2d.py @@ -4,6 +4,7 @@ from diffusion2d import SolveDiffusion2D import pytest +import numpy as np @pytest.fixture @@ -37,8 +38,8 @@ def test_set_initial_condition(solver): """ Checks function SolveDiffusion2D.get_initial_function """ - expected_nx = 50 - expected_ny = 100 + expected_nx = 1000 + expected_ny = 2000 input_w = 100. input_h = 200. @@ -51,4 +52,17 @@ def test_set_initial_condition(solver): solver.initialize_domain(input_w, input_h, input_dx, input_dy) solver.initialize_physical_parameters(expected_D, expected_T_cold, expected_T_hot) - + calculated_u = solver.set_initial_condition() + + expected_u = solver.T_cold * np.ones((expected_nx, expected_ny)) + + r, cx, cy = 2, 5, 5 + r2 = r ** 2 + for i in range(expected_nx): + for j in range(expected_ny): + p2 = (i * input_dx - cx) ** 2 + (j * input_dy - cy) ** 2 + if p2 < r2: + expected_u[i, j] = solver.T_hot + + assert np.array_equal(expected_u, calculated_u) + \ No newline at end of file From afc44b57ab348729385e486af734e1d6896588fe Mon Sep 17 00:00:00 2001 From: Marcel Graf Date: Fri, 16 Jan 2026 16:40:32 +0100 Subject: [PATCH 3/3] Minor adaptions to the tests and correct coverage report --- coverage-report.pdf | Bin 0 -> 53653 bytes requirements.txt | 4 ++++ tests/unit/test_diffusion2d_functions.py | 9 ++++++--- tox.toml | 7 +++++++ 4 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 coverage-report.pdf create mode 100644 requirements.txt create mode 100644 tox.toml diff --git a/coverage-report.pdf b/coverage-report.pdf new file mode 100644 index 0000000000000000000000000000000000000000..bab5ace89189339ae9e29155e2f47bf031bcd778 GIT binary patch literal 53653 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 literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8f87fb4 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +numpy +matplotlib +pytest +coverage \ No newline at end of file diff --git a/tests/unit/test_diffusion2d_functions.py b/tests/unit/test_diffusion2d_functions.py index fbb481a..90e5251 100644 --- a/tests/unit/test_diffusion2d_functions.py +++ b/tests/unit/test_diffusion2d_functions.py @@ -25,7 +25,8 @@ def test_initialize_domain(solver: SolveDiffusion2D): input_dy = 2. solver.initialize_domain(input_w, input_h, input_dx, input_dy) - assert solver.nx == expected_nx and solver.ny == expected_ny + assert solver.nx == expected_nx + assert solver.ny == expected_ny def test_initialize_physical_parameters(solver: SolveDiffusion2D): @@ -43,8 +44,10 @@ def test_initialize_physical_parameters(solver: SolveDiffusion2D): solver.initialize_physical_parameters(expected_D, expected_T_cold, expected_T_hot) - assert solver.T_cold == expected_T_cold and solver.T_hot == expected_T_hot and \ - solver.D == expected_D and solver.dt == pytest.approx(expected_dt, rel=1e-12, abs=0.0) + assert solver.T_cold == expected_T_cold + assert solver.T_hot == expected_T_hot + assert solver.D == expected_D + assert solver.dt == pytest.approx(expected_dt, rel=1e-12, abs=0.0) def test_set_initial_condition(solver: SolveDiffusion2D): diff --git a/tox.toml b/tox.toml new file mode 100644 index 0000000..493bd67 --- /dev/null +++ b/tox.toml @@ -0,0 +1,7 @@ +requires = ["tox>=4"] +env_list = ["pytest_testing"] + +[env.pytest_testing] +description = "Run pytest" +deps = ["-rrequirements.txt"] +commands = [["python", "-m", "pytest"]]