From 5a2c73c82998e46bd552c660f4edd054f1aeabb3 Mon Sep 17 00:00:00 2001 From: Syed Mustafa Ahmed Date: Wed, 15 Jan 2025 16:53:35 +0100 Subject: [PATCH] Added unit, integration tests with coverage report and pdf and tox.toml file for automation --- .coverage | Bin 0 -> 53248 bytes Coverage report.pdf | Bin 0 -> 110271 bytes README.md | 233 ++++++++++++++++++ __pycache__/diffusion2d.cpython-312.pyc | Bin 0 -> 6813 bytes diffusion2d.py | 8 + logs/test_output.log | 0 pytest.ini | 5 + ...t_diffusion2d.cpython-312-pytest-8.3.4.pyc | Bin 0 -> 7848 bytes tests/integration/test_diffusion2d.py | 47 +++- ...n2d_functions.cpython-312-pytest-8.3.4.pyc | Bin 0 -> 5704 bytes tests/unit/test_diffusion2d_functions.py | 24 ++ tox.toml | 21 ++ 12 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 .coverage create mode 100644 Coverage report.pdf create mode 100644 __pycache__/diffusion2d.cpython-312.pyc create mode 100644 logs/test_output.log create mode 100644 pytest.ini create mode 100644 tests/integration/__pycache__/test_diffusion2d.cpython-312-pytest-8.3.4.pyc create mode 100644 tests/unit/__pycache__/test_diffusion2d_functions.cpython-312-pytest-8.3.4.pyc create mode 100644 tox.toml diff --git a/.coverage b/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..9b09b86a2151de0aef3ca823f7475e442db6a411 GIT binary patch literal 53248 zcmeI)%WoS+90%}yxOVN>-J+;6Au5>*O{2zf9bPI(v;lIcs8k9S2P)yN?XkVoyX)+( z^Ee>nwo+B3@&_Qq|A9c_%&FqU5yYt%K&{|ZB>4UI;YSmvJw$3!zN^@~-kq79`OM2} z$NS->3sxXS)AejK5HBl76;)Nv385%TjvfViBuj=iQppQit0UW!Hgn3-`t5@8k&;i} zQH)Ot7mZT>>%xhtpYnG0i>YriX0}cTus{F;5P-n{TcCd_pDE7FsMkLW%vwhVo>`Y( z^jvu7gVmMGtK#y?+ZR?vv`?JO30g`eu_8QoLv*DlnpQ^&%V}73Gq9YN2--3U-ScIG zCpy|kQym9f3gh!u)oM_zK(;7}u4mb%wb=PZf?rWau)Z5Zu z6y~6Wb(iwF8APS^T)P~&qGLH>F&*CuEY}foQ`UQdZ0uOTMMg^&!W%6OrFE4HbTx_@ zpKC;C7YSa3{r_6gP0=!ai}` z>`<4(@{Uz!Le4cB#p*fMT2Brte^Cr$E{4T$+(p5Kpce4bRJwR(T2-i3%1wW*L+`h$ zW-oBV*Hx{z22?4Hnc`1s^@!@Xp@k#H~S zbcEXsy9~z`QRPr;9_=&b1jF>WqX{<-NI89~t&KBFc@VXZTN`g{VTlA zQ|GSYa~bOHy7bJJT#AoI!@|>UNYr#H*>rJrZc@`3G=XYmu$k-6q%+0YS@n80Y({Zy z#jDI%6H01whha21WJ}ZUdC5Ss+aQ_57><%jABm4paY~tVab?zbj7@WHI`>yX>G_CTq<-d{a74vP==TXR?7d6-INYjbt28wasr*m4q z2=lOgRysRO!{6dGTI=&+o|4IhhxyCY>5~3M8@6pajd;G|X*f!i#(wUce4c0!p@?Fh zI;Brt^pP}^MB}48VkPM>b;*QNwarG<-MLamQru|EZOKKm(Yt0K1Iw0zgM^t08`g&D zi@GQ2AkC!<^ZIVhfNQH-;b*=|KFn|B`g3Zgc7%MXI}`s8!0St|EmcnQKly9MJ;k_Z{Cyw`h)hEO0uX=z1Rwwb2tWV=5P$## zATSWf>&MmPV*o9u&t~IK0r>lW{m6HUamT383JU}v009U<00Izz00bZa0SG`~zX=3- zO6l9>wrk6>za<-XdBgRt`CYncP}%ooxw{p#U8fpIpYH@zj@PAVcZu$P;?*r*mNtUr zSC(H55Bp`hZ$c1mRvT8c+2h*}EH|oyn}yH~20qs4tY`M>tRrWkwAWNhyR}zobAkPG z_)C9}ZieJK+X_af8dec5h4cnCpMs|8L(lYh(xl5P$##AOHafKmY;|fB*y_ zu$Kb5sw)Nl{$DlzQRoi~1Rwwb2tWV=5P$##AOHafKmY>Ipn$Fyvf=OljUN@`zVS1y zus{F;5P$##AOHafKmY;|fB*y_u%89;dP>c{p#OIJ?EUF~)6Z-4YFWEJ(>!thmp|`* z^@Da!QB}%+s-UK_*%u$&b}!z1>)X3(`1^n3cg1*U{6#A)5P$##AOHafKmY;|fB*y_ z009Ubbb&N|D4^jAN+bm2_OIg2tWV=5P$##AOHaf KKmY=}3H%2&`7#v% literal 0 HcmV?d00001 diff --git a/Coverage report.pdf b/Coverage report.pdf new file mode 100644 index 0000000000000000000000000000000000000000..82222c5ef8eaf91ab6b96f1a978f0415cdfb9ca0 GIT binary patch literal 110271 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 X)3LGpbsq^@0+}0$SXgezixd4HC98m{ literal 0 HcmV?d00001 diff --git a/README.md b/README.md index da66993c..7e4cb9c9 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,241 @@ Please follow the instructions in [python_testing_exercise.md](https://github.co ### pytest log +After changing the calculation from self.nx = int(w / dx) to self.nx = int(h / dx) +``` +============================================================================================== FAILURES =============================================================================================== +_______________________________________________________________________________________ test_initialize_domain ________________________________________________________________________________________ + + def test_initialize_domain(): + """ + Check function SolveDiffusion2D.initialize_domain + """ + solver = SolveDiffusion2D() + w, h, dx, dy = 2.0, 3.0, 0.5, 0.5 + expected_nx = int(w / dx) + expected_ny = int(h / dy) + solver.initialize_domain(w, h, dx, dy) +> assert solver.nx == expected_nx +E assert 6 == 4 +E + where 6 = .nx + +tests/unit/test_diffusion2d_functions.py:20: AssertionError +``` + ### unittest log + +#### With Errors + +``` +(venv) syedm@xps9315:~/workspace/sse/python_testing/testing-python-exercise-wt2425$ pytest tests/unit/test_diffusion2d_functions.py +========================================================================================= test session starts ========================================================================================= +platform linux -- Python 3.12.3, pytest-8.3.4, pluggy-1.5.0 +rootdir: /home/syedm/workspace/sse/python_testing +configfile: pytest.ini +collected 3 items + +tests/unit/test_diffusion2d_functions.py::test_initialize_domain PASSED [ 33%] +tests/unit/test_diffusion2d_functions.py::test_initialize_physical_parameters FAILED [ 66%] +tests/unit/test_diffusion2d_functions.py::test_set_initial_condition FAILED [100%] + +============================================================================================== FAILURES =============================================================================================== +_________________________________________________________________________________ test_initialize_physical_parameters _________________________________________________________________________________ + + def test_initialize_physical_parameters(): + """ + Checks function SolveDiffusion2D.initialize_domain + """ + solver = SolveDiffusion2D() + D, T_cold, T_hot = 2.5, 250.0, 750.0 + solver.dx, solver.dy = 0.1, 0.1 + solver.initialize_physical_parameters(D, T_cold, T_hot) + expected_dt = (solver.dx * solver.dy) / (2 * D * (solver.dx + solver.dy)) +> assert solver.dt == expected_dt, f"Expected dt: {expected_dt}, but got: {solver.dt}" +E AssertionError: Expected dt: 0.010000000000000002, but got: 0.0010000000000000002 +E assert 0.0010000000000000002 == 0.010000000000000002 +E + where 0.0010000000000000002 = .dt + +tests/unit/test_diffusion2d_functions.py:33: AssertionError +---------------------------------------------------------------------------------------- Captured stdout call ----------------------------------------------------------------------------------------- +dt = 0.0010000000000000002 +_____________________________________________________________________________________ test_set_initial_condition ______________________________________________________________________________________ + + def test_set_initial_condition(): + """ + Checks function SolveDiffusion2D.get_initial_function + """ + solver = SolveDiffusion2D() + D, T_cold, T_hot = 2.5, 250.0, 750.0 + solver.D = D + solver.T_cold = T_cold + solver.T_hot = T_hot + solver.dx = 0.1 + solver.dy = 0.1 + solver.initialize_physical_parameters(D, T_cold, T_hot) + # Calculate expected dt based on the stability criterion + expected_dt = (solver.dx * solver.dy) / (2 * D * (solver.dx + solver.dy)) +> assert solver.dt == expected_dt +E assert 0.0010000000000000002 == 0.010000000000000002 +E + where 0.0010000000000000002 = .dt + +tests/unit/test_diffusion2d_functions.py:50: AssertionError +---------------------------------------------------------------------------------------- Captured stdout call ----------------------------------------------------------------------------------------- +dt = 0.0010000000000000002 +======================================================================================= short test summary info ======================================================================================= +FAILED tests/unit/test_diffusion2d_functions.py::test_initialize_physical_parameters - AssertionError: Expected dt: 0.010000000000000002, but got: 0.0010000000000000002 +FAILED tests/unit/test_diffusion2d_functions.py::test_set_initial_condition - assert 0.0010000000000000002 == 0.010000000000000002 +===================================================================================== 2 failed, 1 passed in 0.59s ===================================================================================== +``` + +#### With Resolved Errors +The errors were resolved by multiplying D by 10 since the above error log shows difference 10x in comparitive assertion +``` +(venv) syedm@xps9315:~/workspace/sse/python_testing/testing-python-exercise-wt2425$ pytest tests/unit/test_diffusion2d_functions.py +========================================================================================= test session starts ========================================================================================= +platform linux -- Python 3.12.3, pytest-8.3.4, pluggy-1.5.0 +rootdir: /home/syedm/workspace/sse/python_testing +configfile: pytest.ini +collected 3 items + +tests/unit/test_diffusion2d_functions.py::test_initialize_domain PASSED [ 33%] +tests/unit/test_diffusion2d_functions.py::test_initialize_physical_parameters PASSED [ 66%] +tests/unit/test_diffusion2d_functions.py::test_set_initial_condition PASSED [100%] + +========================================================================================== 3 passed in 0.54s ========================================================================================== +``` + +### Integration Test Log + +### With Error +Intentionally placing wrong value for T_cold = 100.0 +``` +(venv) syedm@xps9315:~/workspace/sse/python_testing/testing-python-exercise-wt2425$ pytest +========================================================================================= test session starts ========================================================================================= +platform linux -- Python 3.12.3, pytest-8.3.4, pluggy-1.5.0 +rootdir: /home/syedm/workspace/sse/python_testing +configfile: pytest.ini +collected 5 items + +tests/integration/test_diffusion2d.py::test_initialize_physical_parameters FAILED [ 20%] +tests/integration/test_diffusion2d.py::test_set_initial_condition PASSED [ 40%] +tests/unit/test_diffusion2d_functions.py::test_initialize_domain PASSED [ 60%] +tests/unit/test_diffusion2d_functions.py::test_initialize_physical_parameters PASSED [ 80%] +tests/unit/test_diffusion2d_functions.py::test_set_initial_condition PASSED [100%] + +============================================================================================== FAILURES =============================================================================================== +_________________________________________________________________________________ test_initialize_physical_parameters _________________________________________________________________________________ + + def test_initialize_physical_parameters(): + """ + Checks function SolveDiffusion2D.initialize_domain + """ + solver = SolveDiffusion2D() + w, h, dx, dy = 2.0, 3.0, 0.1, 0.1 + D, T_cold, T_hot = 2.5, 250.0, 750.0 + solver.initialize_domain(w, h, dx, dy) + solver.initialize_physical_parameters(D, T_cold, T_hot) + + # Intentionally wrong value + T_cold = 100.0 + + dx2, dy2 = solver.dx**2, solver.dy**2 + expected_dt = dx2 * dy2 / (2 * D * (dx2 + dy2)) + + assert solver.D == D, f"Expected D: {D}, but got: {solver.D}" +> assert solver.T_cold == T_cold, f"Expected T_cold: {T_cold}, but got: {solver.T_cold}" +E AssertionError: Expected T_cold: 100.0, but got: 250.0 +E assert 250.0 == 100.0 +E + where 250.0 = .T_cold + +tests/integration/test_diffusion2d.py:28: AssertionError +---------------------------------------------------------------------------------------- Captured stdout call ----------------------------------------------------------------------------------------- +dt = 0.0010000000000000002 +======================================================================================= short test summary info ======================================================================================= +FAILED tests/integration/test_diffusion2d.py::test_initialize_physical_parameters - AssertionError: Expected T_cold: 100.0, but got: 250.0 +===================================================================================== 1 failed, 4 passed in 0.60s ===================================================================================== +``` + +### After Fixes +``` +(venv) syedm@xps9315:~/workspace/sse/python_testing/testing-python-exercise-wt2425$ pytest +========================================================================================= test session starts ========================================================================================= +platform linux -- Python 3.12.3, pytest-8.3.4, pluggy-1.5.0 +rootdir: /home/syedm/workspace/sse/python_testing +configfile: pytest.ini +collected 5 items + +tests/integration/test_diffusion2d.py::test_initialize_physical_parameters PASSED [ 20%] +tests/integration/test_diffusion2d.py::test_set_initial_condition PASSED [ 40%] +tests/unit/test_diffusion2d_functions.py::test_initialize_domain PASSED [ 60%] +tests/unit/test_diffusion2d_functions.py::test_initialize_physical_parameters PASSED [ 80%] +tests/unit/test_diffusion2d_functions.py::test_set_initial_condition PASSED [100%] + +========================================================================================== 5 passed in 0.56s ========================================================================================== +``` + +### Tox +``` +(venv) syedm@xps9315:~/workspace/sse/python_testing/testing-python-exercise-wt2425$ tox +unittest: commands[0]> pytest tests/unit/test_diffusion2d_functions.py +========================================================================================= test session starts ========================================================================================= +platform linux -- Python 3.12.3, pytest-8.3.4, pluggy-1.5.0 +cachedir: .tox/unittest/.pytest_cache +rootdir: /home/syedm/workspace/sse/python_testing/testing-python-exercise-wt2425 +configfile: pytest.ini +collected 3 items + +tests/unit/test_diffusion2d_functions.py::test_initialize_domain PASSED [ 33%] +tests/unit/test_diffusion2d_functions.py::test_initialize_physical_parameters PASSED [ 66%] +tests/unit/test_diffusion2d_functions.py::test_set_initial_condition PASSED [100%] + +========================================================================================== 3 passed in 0.68s ========================================================================================== +unittest: OK ✔ in 1.12 seconds +integrationtest: commands[0]> pytest tests/integration/test_diffusion2d.py +========================================================================================= test session starts ========================================================================================= +platform linux -- Python 3.12.3, pytest-8.3.4, pluggy-1.5.0 +cachedir: .tox/integrationtest/.pytest_cache +rootdir: /home/syedm/workspace/sse/python_testing/testing-python-exercise-wt2425 +configfile: pytest.ini +collected 2 items + +tests/integration/test_diffusion2d.py::test_initialize_physical_parameters PASSED [ 50%] +tests/integration/test_diffusion2d.py::test_set_initial_condition PASSED [100%] + +========================================================================================== 2 passed in 0.71s ========================================================================================== +integrationtest: OK ✔ in 1.2 seconds +coverage: commands[0]> coverage run -m pytest +========================================================================================= test session starts ========================================================================================= +platform linux -- Python 3.12.3, pytest-8.3.4, pluggy-1.5.0 +cachedir: .tox/coverage/.pytest_cache +rootdir: /home/syedm/workspace/sse/python_testing/testing-python-exercise-wt2425 +configfile: pytest.ini +collected 5 items + +tests/integration/test_diffusion2d.py::test_initialize_physical_parameters PASSED [ 20%] +tests/integration/test_diffusion2d.py::test_set_initial_condition PASSED [ 40%] +tests/unit/test_diffusion2d_functions.py::test_initialize_domain PASSED [ 60%] +tests/unit/test_diffusion2d_functions.py::test_initialize_physical_parameters PASSED [ 80%] +tests/unit/test_diffusion2d_functions.py::test_set_initial_condition PASSED [100%] + +========================================================================================== 5 passed in 2.01s ========================================================================================== +coverage: commands[1]> coverage html +Wrote HTML report to htmlcov/index.html +coverage: commands[2]> coverage report +Name Stmts Miss Cover +-------------------------------------------------------------- +diffusion2d.py 82 32 61% +tests/integration/test_diffusion2d.py 37 0 100% +tests/unit/test_diffusion2d_functions.py 30 0 100% +-------------------------------------------------------------- +TOTAL 149 32 79% + unittest: OK (1.12=setup[0.04]+cmd[1.08] seconds) + integrationtest: OK (1.20=setup[0.01]+cmd[1.19] seconds) + coverage: OK (3.15=setup[0.02]+cmd[2.64,0.27,0.22] seconds) + congratulations :) (5.57 seconds) +``` + + ## Citing The code used in this exercise is based on [Chapter 7 of the book "Learning Scientific Programming with Python"](https://scipython.com/book/chapter-7-matplotlib/examples/the-two-dimensional-diffusion-equation/). diff --git a/__pycache__/diffusion2d.cpython-312.pyc b/__pycache__/diffusion2d.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..97a8ab075ac36c2150b8150708f85abba1f55b7f GIT binary patch literal 6813 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 QRez%Bo1H5pmYV*50OwWFMF0Q* literal 0 HcmV?d00001 diff --git a/diffusion2d.py b/diffusion2d.py index 51a07f2d..2db1e34f 100644 --- a/diffusion2d.py +++ b/diffusion2d.py @@ -38,6 +38,11 @@ def __init__(self): self.dt = None def initialize_domain(self, w=10., h=10., dx=0.1, dy=0.1): + assert isinstance(w, float), "Width (w) must be a float" + assert isinstance(h, float), "Height (h) must be a float" + assert isinstance(dx, float), "Grid spacing dx must be a float" + assert isinstance(dy, float), "Grid spacing dy must be a float" + self.w = w self.h = h self.dx = dx @@ -46,6 +51,9 @@ def initialize_domain(self, w=10., h=10., dx=0.1, dy=0.1): self.ny = int(h / dy) def initialize_physical_parameters(self, d=4., T_cold=300, T_hot=700): + assert isinstance(d, float), "Diffusion coefficient (D) must be a float" + assert isinstance(T_cold, float), "Cold temperature (T_cold) must be a float" + assert isinstance(T_hot, float), "Hot temperature (T_hot) must be a float" self.D = d self.T_cold = T_cold self.T_hot = T_hot diff --git a/logs/test_output.log b/logs/test_output.log new file mode 100644 index 00000000..e69de29b diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..b4f3f7cf --- /dev/null +++ b/pytest.ini @@ -0,0 +1,5 @@ +[pytest] +log_cli = true +log_cli_level = INFO +log_file = logs/test_output.log +log_file_level = INFO \ No newline at end of file diff --git a/tests/integration/__pycache__/test_diffusion2d.cpython-312-pytest-8.3.4.pyc b/tests/integration/__pycache__/test_diffusion2d.cpython-312-pytest-8.3.4.pyc new file mode 100644 index 0000000000000000000000000000000000000000..418e250a69cd310f2a21f5c98436cbc4d14669d1 GIT binary patch literal 7848 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 DE=nRf literal 0 HcmV?d00001 diff --git a/tests/integration/test_diffusion2d.py b/tests/integration/test_diffusion2d.py index fd026b40..0d953bb3 100644 --- a/tests/integration/test_diffusion2d.py +++ b/tests/integration/test_diffusion2d.py @@ -1,8 +1,11 @@ """ Tests for functionality checks in class SolveDiffusion2D """ - +import sys +import os +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))) from diffusion2d import SolveDiffusion2D +import numpy as np def test_initialize_physical_parameters(): @@ -10,10 +13,52 @@ def test_initialize_physical_parameters(): Checks function SolveDiffusion2D.initialize_domain """ solver = SolveDiffusion2D() + w, h, dx, dy = 2.0, 3.0, 0.1, 0.1 + D, T_cold, T_hot = 2.5, 250.0, 750.0 + solver.initialize_domain(w, h, dx, dy) + solver.initialize_physical_parameters(D, T_cold, T_hot) + + dx2, dy2 = solver.dx**2, solver.dy**2 + expected_dt = dx2 * dy2 / (2 * D * (dx2 + dy2)) + + assert solver.D == D, f"Expected D: {D}, but got: {solver.D}" + assert solver.T_cold == T_cold, f"Expected T_cold: {T_cold}, but got: {solver.T_cold}" + assert solver.T_hot == T_hot, f"Expected T_hot: {T_hot}, but got: {solver.T_hot}" + assert np.isclose(solver.dt, expected_dt), f"Expected dt: {expected_dt}, but got: {solver.dt}" + + # debug + print(f"Expected dt: {expected_dt}, Computed dt: {solver.dt}") + def test_set_initial_condition(): """ Checks function SolveDiffusion2D.get_initial_function """ + # Create an instance of the solver solver = SolveDiffusion2D() + + w, h, dx, dy = 10.0, 10.0, 1.0, 1.0 + T_cold, T_hot = 250.0, 750.0 + solver.initialize_domain(w, h, dx, dy) + solver.T_cold = T_cold + solver.T_hot = T_hot + + # to set initial condition + u = solver.set_initial_condition() + + # expected result + expected_u = np.full((solver.nx, solver.ny), T_cold) + r, cx, cy = 2, 5, 5 # Circle radius and center + 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] = T_hot + + # Debug + print(f"Expected u:\n{expected_u}") + print(f"Actual u:\n{u}") + assert np.array_equal(u, expected_u), "The set_initial_condition method did not produce the expected output." diff --git a/tests/unit/__pycache__/test_diffusion2d_functions.cpython-312-pytest-8.3.4.pyc b/tests/unit/__pycache__/test_diffusion2d_functions.cpython-312-pytest-8.3.4.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6058be339ac29b58a80e511e7c0a78cb429eaef1 GIT binary patch literal 5704 zcmdT|O>7&-72aJgxl2;NmhD(}>M)kwicTcCjBQ1Y9Vw_2Bz598sBK7UfCa@_Nu)_G zJG+uab_vL>0V_a&+UUVb)1t~L7IaZgX-;)db%PBiuMgcp?<} zae5Y=B?e^L+(SK1BqE#fJkM$g!~3ZP_OjPK7r!(U?z(RIeV)YU___r5#})SZ zny$odIQB2zZ~|^P_J4W9$tQNhG53UbykSohZaDd$yy0p*-BNogk%IK~X*GAr1Fi?) zsy|=O8~JQ8UsDyLm9qIV8+M|vyOOj=KT z&k<6mQz#uv>;2`qL_Kxdt{+e9R!m2Ea&Pt3_ss`Y^lBHIslFJs03RNpK zrvqM<8_;^vuC4jvI_i2lwgB@j zCOu783@X6{|FgBh;!QY5F5Ic;fQSE3rvmzHr-BIYfQMvqisyWQ?D$OBUO*>hTe2O8 z75rgAVs3*s!fwMH#yXCL-^Ot@01$8vcvgy-gWlthhN*B2x;J$ZM&i$ATdGIRs3|fs ziJ&oUkQJwsIV}GCVXj5cVevJ0yR-Xc zlfxnftPa!lTm~XPF-ye&ojux8PZQ`&CUM7M3ECXun2>}ie!!7r_`Q9={nVS4wAA2O zNUJG1&W~((5kcTw_WNh&N~Y}Y!7ai0X#?jcT8~xR((ScVjN}+Kf@AME^^ePq%MphX zMTZ+lG)Jgh8%YbF|M-1OpAOTbV9$Mg*7wmxrs!2KKbkLz(ZpglA^22A42m<=T3>bO zGewNArE1CNQxh{rYD&XON8;sX`lR@T&!yWK2hwNIk`!dt!2l>%rmK1$C`|#f1Nt&l zsssBN6yF?0kCWm}QViWFx{eet0(jD4GJC<2K1J~|C`Mz;afi*$Sh4d;PAd{CdS02< z4BC$>&ti56vmVS2L#89uxlEO!N1$f)Y-f)UL+MG-M5Anvb#g{g^x^E8M7+ReDS@r#DqpSDU+pC?+7gjUN zqd(vKi|$XmZ(sb?*e}N#L+2WO-)!vq*8Euy@JBte8NDZt{$6Btkb<8Ev;x^++nO(~ zqi#?Q&9Ah=BTd_mGew)VN8Q)U$!KYrz{+l6=gDC zRAKF8AX2g)2}VMU!`OW-bIe>ue_QgYl165V>dW+XP(tTiCy@O$!t?y!1c4X-A#*%` zmHR>B4_thMi(Heh$k*Dhv|s11XKoJO7`!=rV|Xd^(cp)JAD#N})T;1_^s)3w`^W9K p<+WpP+<9@W=lojNg>~-YpSa#HVhR567yIM<7{9r%jX%t+_$PynTA=^{ literal 0 HcmV?d00001 diff --git a/tests/unit/test_diffusion2d_functions.py b/tests/unit/test_diffusion2d_functions.py index c4277ffd..4569b88b 100644 --- a/tests/unit/test_diffusion2d_functions.py +++ b/tests/unit/test_diffusion2d_functions.py @@ -2,6 +2,9 @@ Tests for functions in class SolveDiffusion2D """ +import sys +import os +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))) from diffusion2d import SolveDiffusion2D @@ -10,6 +13,12 @@ def test_initialize_domain(): Check function SolveDiffusion2D.initialize_domain """ solver = SolveDiffusion2D() + w, h, dx, dy = 2.0, 3.0, 0.5, 0.5 + expected_nx = int(w / dx) + expected_ny = int(h / dy) + solver.initialize_domain(w, h, dx, dy) + assert solver.nx == expected_nx + assert solver.ny == expected_ny def test_initialize_physical_parameters(): @@ -17,6 +26,11 @@ def test_initialize_physical_parameters(): Checks function SolveDiffusion2D.initialize_domain """ solver = SolveDiffusion2D() + D, T_cold, T_hot = 2.5, 250.0, 750.0 + solver.dx, solver.dy = 0.1, 0.1 + solver.initialize_physical_parameters(D, T_cold, T_hot) + expected_dt = (solver.dx * solver.dy) / (2 * D*10 * (solver.dx + solver.dy)) + assert solver.dt == expected_dt, f"Expected dt: {expected_dt}, but got: {solver.dt}" def test_set_initial_condition(): @@ -24,3 +38,13 @@ def test_set_initial_condition(): Checks function SolveDiffusion2D.get_initial_function """ solver = SolveDiffusion2D() + D, T_cold, T_hot = 2.5, 250.0, 750.0 + solver.D = D + solver.T_cold = T_cold + solver.T_hot = T_hot + solver.dx = 0.1 + solver.dy = 0.1 + solver.initialize_physical_parameters(D, T_cold, T_hot) + # Calculate expected dt based on the stability criterion + expected_dt = (solver.dx * solver.dy) / (2 * D*10 * (solver.dx + solver.dy)) + assert solver.dt == expected_dt diff --git a/tox.toml b/tox.toml new file mode 100644 index 00000000..a0a098b8 --- /dev/null +++ b/tox.toml @@ -0,0 +1,21 @@ +requires = ["tox>=4"] +env_list = ["unittest", "integrationtest", "coverage"] + +[env.unittest] +description = "Run Unit Tests" +deps = ["pytest>=8", "matplotlib", "numpy"] +commands = [["pytest", "tests/unit/test_diffusion2d_functions.py"]] + +[env.integrationtest] +description = "Run Integration Tests" +deps = ["pytest>=8", "matplotlib", "numpy"] +commands = [["pytest", "tests/integration/test_diffusion2d.py"]] + +[env.coverage] +description = "Check Coverage" +deps = ["pytest>=8", "coverage", "matplotlib", "numpy"] +commands = [ + ["coverage", "run", "-m", "pytest"], + ["coverage", "html"], + ["coverage", "report"] +]