- Exercise repository link
- Deadline for submitting this exercise is Wednesday 21st January 2026 09:00.
- Fork the repository.
- The code in
diffusion2d.pyis in principle the same code used for the packaging exercise. The main difference is that now the code has a classSolveDiffusion2Dwhich has several member functions. - Each function name states what the function does, for example the function
initialize_domain()takes in input argumentsw(width),h(height),dxanddyand sets the values to member variables of the class and also calculates the number of points in x and y directions. - The functions
initialize_domainandinitialize_physical_parametershave default values for all input parameters, hence they can be called without any parameters. - The file also has a
main()function which shows a step-by-step procedure to solve the diffusion problem using an object of the classSolveDiffusion2D. - Make sure that
NumPyandMatplotlibare installed on the system that you are working on. - Run this example by running
python3 diffusion2d.py. - Observe the output produced, it should be the same output as what was seen during the packaging exercise.
- Add assertion statements to the functions
initialize_domainandinitialize_physical_parameterswhich check whether all input parameters are double precision/floats. - Rerun the code after inserting all the assertion statements? Does the code break? Which parameters are problematic?
- The default values of some of the input parameters like
T_hotandT_coldare in fact integers and need to be changed. Change these values to floats and rerun the code to make sure that all assertions are returning true.
- Write unit tests using either pytest or unittest.
- In the repository there is a folder
tests/. In this folder there are two foldersunit/andintegration/. Write the unit tests first. - In the file
tests/unit/test_diffusion2d_functions.pythere is already a skeleton code for three unit tests. The name of each test is of the formattest_<name_of_function_being_tested>. - As these are unit tests, in each test, only the call to the respective function needs to be made. No other function from
diffusion2d.pymust be called. If another function call is required to define some member variables, mock it or directly define the internal variables. - As an example, let us look at how we can write a unit test for the function
initialize_domain.- When the function
initialize_domainis being tested, you need to first identify which variables are being calculated in this function. - In this case they are the variables
nxandny. Now choose some values for the variablesw,h,dx, anddywhich are different from the default values. For these values, manually calculate the values ofnxandny. These manually calculated values are the expected values in this test. - Now call the function
initialize_domainwith the chosen values ofw,h,dx, anddyand using an assertion statement, check if the values ofnxandnyin the class member variables are equal to your expected values. - Note that you have the object of the class
SolveDiffusion2Dand hence you can access member variables, for examplesolver.nxandsolver.ny. This is useful to check the actual values.
- When the function
- Using a similar workflow, complete the other two unit tests.
- Sometimes pytest is not able to find the tests. One reason is the way pytest is installed, which is typically either using pip or apt. Refer to the corresponding section in the demo for more details. If such errors occur, then try to explicitly point pytest to the relevant test file in the following way:
pytest tests/unit/test_diffusion2d_functions.py-
How can you make sure that you have written correct tests? By breaking them purposely!
- Introduce a bug in a function on purpose and then re-run the test to see if the test fails.
- Lets try this in the function
initialize_domain. In line 42 ofdiffusion2d.py, change the calculation fromself.nx = int(w / dx)toself.nx = int(h / dx). This is clearly a mistake and our test should catch it. - Now run the tests again. Did the test catch the bug? If yes, then you have written the test correctly. If the test does not catch the bug, try to think why did it not? Is your choice of values for the parameters
w,h,dxanddyresponsible for it? If the test is run withw = hthen this bug will not be caught. What do we learn from this? We learn that the test fixture should be as general as possible and we should ensure that we are not testing special scenarios. A domain withw = his a square domain which is a special case of a rectangular domain with arbitrary values forwandh.
-
If you are writing tests with unittest, start by creating a class
TestDiffusion2Dwhich is derived from the classunittest.TestCase. Migrate all the tests inside the class and change them to be member functions of the class. Note that the parameterselfneeds to be used in the input parameters of all member functions and also while defining and using member variables. -
Identify the common steps necessary in all the tests and transfer the functionality to the function
setUp. One example of this is the definition of the object of classSolveDiffusion2D. -
The main change is in the assertion statements. Change the assertion statements to the format as required by
unittest. Refer to the lecture demo for an example on how to do this.
- Write integration tests will be written for the functions
initialize_physical_parametersandset_initial_conditions. As these are integration tests, each test should check how different functions fromSolveDiffusion2Dwork together. - For example, let us look at how the test for
initialize_physical_parameterswill look like.- First step is to select some values for the input parameters to the function
initialize_physical_parametersand also the functioninitialize_domain. - Looking at the functionality in
initialize_physical_parameterswe understand that the most relevant variable being calculated isdt. - Based on the choice of all input parameters, manually compute the value of
dtfor the test. This is the expected result. - Call the function
initialize_domainand then the functioninitialize_physical_parameters. - Compare the value of the member variable
dtwith the manually computeddtusing an assertion statement.
- First step is to select some values for the input parameters to the function
- Now also write a similar integration test for
set_initial_conditions. Note that this will be the most extensive test from the whole set. The field variableuis computed inset_initial_conditions, which is a 2D array. The test should have a computation which computes a similaruarray for a user-defined set of initial parameters. This computeduis the expected result. - Using the same logic as in the previous steps, intentionally break the tests to make sure that the tests are constructed correctly.
- Using the coverage tool generate a HTML report of the code coverage of all the tests.
- Open the report file in a browser and print the report to a file called
coverage-report.pdf. Add this file to the repository.
- Write a
tox.tomlfile such that by running the commandtox, the tests are run using pytest and/or unittest in separate virtual environments. - Use the
requirements.txtfile to send all the dependencies information to tox.
- Open a pull request titled
[<your GitLab username>] Adding tests(for example:[desaiin] Adding tests) from your fork to the main branch of the exercise repository.