How to create unitary tests

From KratosWiki
(Difference between revisions)
Jump to: navigation, search
(How to run tests)
Line 1: Line 1:
<span style="color: red"> Under construction </span>
+
Kratos Multiphysics has a mechanism to automatically test your code called "KratosUnittest". If you are familiar with python, this module is basically an extension of Unittest[https://docs.python.org/2/library/unittest.html] and you can expect to find every functionality that exists on in as well in KratosUnittest.
  
Kratos Multiphysics has a mechanism to automatically test your code called "KratosUnittest". If you are familiar with python, this module is basically an extension of Unittest and you can expect to find every functionality that exists on in as well in KratosUnittest.
+
In order for your application to be robust, is recommended that you add unittests to it. Here we present some guidelines on how to do it.
 
+
In order for your application to be robust, is recommemded that you add unittests to it. Here we present some guidelines on how to do it.
+
  
 
== How to run tests ==
 
== How to run tests ==
Line 43: Line 41:
 
  kratos/applications/example_application/tests/test_example_application.py
 
  kratos/applications/example_application/tests/test_example_application.py
  
 +
= General structure =
  
 
This file will define the suites to run the tests. We define three different levels of suites in kratos:
 
This file will define the suites to run the tests. We define three different levels of suites in kratos:
Line 106: Line 105:
 
  if __name__ == '__main__':
 
  if __name__ == '__main__':
 
     KratosUnittest.runTests(AssambleTestSuites())
 
     KratosUnittest.runTests(AssambleTestSuites())
 +
 +
= Structure for examples =
 +
 +
In order to compute some examples (the examples that use to be located in the folder "test_examples") some additional considerations must to be taken into account. These considerations can be observed in the following example that is located in the StructuralMechanicsApplication. In order to compute a Patch Test, with bending and membrane    behaviours, the following files has been considered, first the main file that will be the one launched.
 +
 +
    # import Kratos
 +
    from KratosMultiphysics import *
 +
    from KratosMultiphysics.SolidMechanicsApplication import *
 +
    from KratosMultiphysics.StructuralMechanicsApplication import *
 +
   
 +
    # Import Kratos "wrapper" for unittests
 +
    import KratosMultiphysics.KratosUnittest as KratosUnittest
 +
   
 +
    # Import the tests o test_classes to create the suits
 +
    from SmallTests import SprismTests as TSprismTests
 +
   
 +
    def AssambleTestSuites():
 +
        ''' Populates the test suites to run.
 +
   
 +
        Populates the test suites to run. At least, it should pupulate the suites:
 +
        "small", "nighlty" and "all"
 +
   
 +
        Return
 +
        ------
 +
   
 +
        suites: A dictionary of suites
 +
            The set of suites with its test_cases added.
 +
        '''
 +
        suites = KratosUnittest.KratosSuites
 +
   
 +
        # Create a test suit with the selected tests (Small tests):
 +
        smallSuite = suites['small']
 +
        smallSuite.addTest(TSprismTests('test_MembranePacth'))
 +
        smallSuite.addTest(TSprismTests('test_BendingPacth'))
 +
   
 +
        # Create a test suit with the selected tests plus all small tests
 +
        nightSuite = suites['nightly']
 +
        nightSuite.addTests(smallSuite)
 +
   
 +
        # Create a test suit that contains all the tests:
 +
        allSuite = suites['all']
 +
        allSuite.addTests(
 +
            KratosUnittest.TestLoader().loadTestsFromTestCases([
 +
                TSprismTests
 +
            ])
 +
        )
 +
   
 +
        return suites
 +
   
 +
    if __name__ == '__main__':
 +
        KratosUnittest.runTests(AssambleTestSuites())
 +
 +
 +
The following corresponds with the Script that content the test examples:
 +
   
 +
    # Import Kratos
 +
    from KratosMultiphysics import *
 +
    from KratosMultiphysics.SolidMechanicsApplication import *
 +
    from KratosMultiphysics.StructuralMechanicsApplication import *
 +
   
 +
    # Import KratosUnittest
 +
    import KratosMultiphysics.KratosUnittest as KratosUnittest
 +
   
 +
    # Additional imports
 +
    import constitutive_law_python_utility as constitutive_law_utils
 +
   
 +
    def GetFilePath(fileName):
 +
        return os.path.dirname(__file__) + "/" + fileName
 +
   
 +
    class SprismTests(KratosUnittest.TestCase):
 +
   
 +
        def setUp(self):
 +
            # Modelpart for the solid
 +
            model_part = ModelPart("StructuralPart")
 +
            model_part.AddNodalSolutionStepVariable(ALPHA_EAS)
 +
            model_part.AddNodalSolutionStepVariable(DISPLACEMENT)
 +
            model_part.AddNodalSolutionStepVariable(REACTION)
 +
   
 +
            # Initialize GiD  I/O
 +
            input_file_name = GetFilePath("SPRISM3D6N/patch_test")
 +
   
 +
            # Reading the fluid part
 +
            model_part_io_fluid = ModelPartIO(input_file_name)
 +
            model_part_io_fluid.ReadModelPart(model_part)
 +
           
 +
            # Find neighbours if required
 +
            sprism_neighbour_search = SprismNeighbours(model_part)
 +
            sprism_neighbour_search.Execute()
 +
   
 +
            # Setting up the buffer size
 +
            model_part.SetBufferSize(3)
 +
   
 +
            # Adding dofs
 +
            for node in model_part.Nodes:
 +
            node.AddDof(DISPLACEMENT_X, REACTION_X)
 +
            node.AddDof(DISPLACEMENT_Y, REACTION_Y)
 +
            node.AddDof(DISPLACEMENT_Z, REACTION_Z)
 +
           
 +
            # Set the constitutive law
 +
            constitutive_law = constitutive_law_utils.ConstitutiveLawUtility(model_part, 3);
 +
            constitutive_law.Initialize();
 +
   
 +
            max_iters = 30
 +
   
 +
            linear_solver = SkylineLUFactorizationSolver()
 +
   
 +
            # Create solver
 +
            builder_and_solver = ResidualBasedBuilderAndSolver(linear_solver)
 +
            mechanical_scheme = ResidualBasedStaticScheme()
 +
            mechanical_convergence_criterion = ResidualCriteria(1e-4, 1e-4)
 +
   
 +
            self.mechanical_solver = ResidualBasedNewtonRaphsonStrategy(
 +
                model_part,
 +
                mechanical_scheme,
 +
                linear_solver,
 +
                mechanical_convergence_criterion,
 +
                builder_and_solver,
 +
                max_iters,
 +
                False ,
 +
                True,
 +
                True)
 +
   
 +
            self.mechanical_solver.SetEchoLevel(0)
 +
            self.mechanical_solver.Initialize()
 +
   
 +
            self.model_part = model_part
 +
   
 +
        def test_MembranePacth(self):
 +
            step = 0
 +
            time = 0.0
 +
            Dt = 1.0
 +
            final_time = 1.0
 +
   
 +
            # Add BC
 +
            for node in self.model_part.Nodes:
 +
                if (node.X >2.40000e-01 -1.0e-5) | (node.Y > 1.20000e-01 -1.0e-5) | (node.X < 1.0e-5) | (node.Y < 1.0e-5):
 +
                    node.Fix(DISPLACEMENT_X)
 +
                    node.SetSolutionStepValue(
 +
                        DISPLACEMENT_X,
 +
                        0,
 +
                        1.0e-7 * (node.X + node.Y / 2))
 +
                    node.Fix(DISPLACEMENT_Y)
 +
                    node.SetSolutionStepValue(
 +
                        DISPLACEMENT_Y,
 +
                        0,
 +
                        1.0e-7 * (node.Y + node.X / 2))
 +
   
 +
            while(time <= final_time):
 +
   
 +
                self.model_part.CloneTimeStep(time)
 +
   
 +
                time += Dt
 +
                step += 1
 +
   
 +
                self.mechanical_solver.Solve()
 +
   
 +
            for node in self.model_part.Nodes:
 +
                value = node.GetSolutionStepValue(DISPLACEMENT_X,0)
 +
                self.assertAlmostEqual(value, 1.0e-7 * (node.X + node.Y / 2))
 +
                value = node.GetSolutionStepValue(DISPLACEMENT_Y,0)
 +
                self.assertAlmostEqual(value, 1.0e-7 * (node.Y + node.X / 2))
 +
   
 +
        def test_BendingPacth(self):
 +
            step = 0
 +
            time = 0.0
 +
            Dt = 1.0
 +
            final_time = 1.0
 +
   
 +
            # Add BC
 +
            for node in self.model_part.Nodes:
 +
                if (node.X >2.40000e-01 -1.0e-5) | (node.Y > 1.20000e-01 -1.0e-5) | (node.X < 1.0e-5) | (node.Y < 1.0e-5):
 +
                    node.Fix(DISPLACEMENT_X)
 +
                    node.SetSolutionStepValue(
 +
                        DISPLACEMENT_X, 0,
 +
                        -1.0e-7 * (node.Z - 0.0005) * (node.X + node.Y / 2))
 +
                    node.Fix(DISPLACEMENT_Y)
 +
                    node.SetSolutionStepValue(
 +
                        DISPLACEMENT_Y, 0,
 +
                        -1.0e-7 * (node.Z - 0.0005) * (node.Y + node.X / 2))
 +
                    node.Fix(DISPLACEMENT_Z)
 +
                    node.SetSolutionStepValue(
 +
                        DISPLACEMENT_Z, 0,
 +
                        0.5 * 1.0e-7 * (node.X ** 2 + node.X * node.Y + node.Y ** 2))
 +
   
 +
            while(time <= final_time):
 +
   
 +
                self.model_part.CloneTimeStep(time)
 +
   
 +
                time += Dt
 +
                step += 1
 +
               
 +
                self.mechanical_solver.Solve()
 +
   
 +
            for node in self.model_part.Nodes:
 +
                value = node.GetSolutionStepValue(DISPLACEMENT_X,0)
 +
                self.assertAlmostEqual(
 +
                    value,
 +
                    -1.0e-7 * (node.Z - 0.0005) * (node.X + node.Y / 2))
 +
                value = node.GetSolutionStepValue(DISPLACEMENT_Y,0)
 +
                self.assertAlmostEqual(
 +
                    value,
 +
                    -1.0e-7 * (node.Z - 0.0005) * (node.Y + node.X / 2))
 +
                value = node.GetSolutionStepValue(DISPLACEMENT_Z,0)
 +
                self.assertAlmostEqual(value,
 +
                    0.5 * 1.0e-7 * (node.X ** 2 + node.X * node.Y + node.Y **2 ))
 +
 +
        def tearDown(self):
 +
            pass
 +
 +
You can download this example from here
 +
 +
= Some common commands in Unittest=

Revision as of 21:12, 12 April 2016

Kratos Multiphysics has a mechanism to automatically test your code called "KratosUnittest". If you are familiar with python, this module is basically an extension of Unittest[1] and you can expect to find every functionality that exists on in as well in KratosUnittest.

In order for your application to be robust, is recommended that you add unittests to it. Here we present some guidelines on how to do it.

Contents

How to run tests

Kratos unittest are executed using the "run_tests.py" script located in the "kratos/kratos/python_scripts" folder.

Usage is the following:

python run_tests.py

you can specify the following options:

-l,--level:        Select the suit. Values: "All", "Nighlty", "Small"(default)
-v,--vervosity:    Select the vervosity level of the output. Values: 0, 1 (default) , 2
-a,--applications: List of applications to run separated by ":". For example "-a KratosKore:IncompresibleFluidApplication"
                   All applications compiled are run by default.

Basic structure

Tests are defined in a python script. To keep tests organized we recommend you to create the tests in your "application/tests/" directory.

Tests are organized in suites. Suites are collection of tests that will be run together as a package. In Kratos, we define three basic suites:

  • All: which should contain all the tests
  • Nighlty: which should contain a set of tests that could be executed in less than 10 min
  • Small: which should contain a set of tests that could be executed in less than 1 min


All applications should implement this packages as they can be automatically run, for example in the "nighlty" runs. In order to add tests you should create at least a couple of files, one to define the tests

and one to define the suits:

"application/tests/test_NAME_OF_OUR_APPLICATION.py"


for example:

kratos/applications/example_application/tests/test_example_application.py

General structure

This file will define the suites to run the tests. We define three different levels of suites in kratos:

  • All: which should contain all the tests
  • Nighlty: which should contain a set of tests that could be executed in less than 10 min
  • Small: which should contain a set of tests that could be executed in less than 1 min


In order to add test to some of these suits, one can do it as shown in this example:

from __future__ import print_function, absolute_import, division

# import Kratos
from KratosMultiphysics import *

# Import Kratos "wrapper" for unittests
import KratosMultiphysics.KratosUnittest as KratosUnittest

# Import the tests o test_classes to create the suites. For example
from test_my_app_example_tests_1 import TestCase1 as TestCase1
from test_my_app_example_tests_2 import TestCase2 as TestCase2

def AssambleTestSuites():
     Populates the test suites to run.
    
    Populates the test suites to run. At least, it should pupulate the suites:
    "small", "nighlty" and "all"
    
    Return
    ------
    
    suites: A dictionary of suites
        The set of suites with its test_cases added.
    
    
    # Get the already defined suits
    suites = KratosUnittest.KratosSuites
    
    # Get the small suit and populate it with some tests from TestCase1 and TestCase2
    smallSuite = suites['small']
    smallSuite.addTest(TestCase1('test_example_small_boo_1'))
    smallSuite.addTest(TestCase2('test_example_small_foo_1'))
    
    # Get the small suit and populate it with some tests from TestCase1 and TestCase2
    nightSuite = suites['nightly']
    smallSuite.addTest(TestCase1('test_example_nightly_boo_1'))
    smallSuite.addTest(TestCase1('test_example_nightly_boo_2'))
    smallSuite.addTest(TestCase2('test_example_nightly_foo_1'))
    
    # Get the small suit and populate it with all tests from TestCase1 and TestCase2
    allSuite = suites['all']
    allSuite.addTests(
        KratosUnittest.TestLoader().loadTestsFromTestCases([
            TestCase1,
            TestCase2
        ])
    )
    
    # Return the suites
    return suites
    
# The main function executes the tests
if __name__ == '__main__':
    KratosUnittest.runTests(AssambleTestSuites())

Structure for examples

In order to compute some examples (the examples that use to be located in the folder "test_examples") some additional considerations must to be taken into account. These considerations can be observed in the following example that is located in the StructuralMechanicsApplication. In order to compute a Patch Test, with bending and membrane behaviours, the following files has been considered, first the main file that will be the one launched.

   # import Kratos
   from KratosMultiphysics import *
   from KratosMultiphysics.SolidMechanicsApplication import *
   from KratosMultiphysics.StructuralMechanicsApplication import *
   
   # Import Kratos "wrapper" for unittests
   import KratosMultiphysics.KratosUnittest as KratosUnittest
   
   # Import the tests o test_classes to create the suits
   from SmallTests import SprismTests as TSprismTests
   
   def AssambleTestSuites():
        Populates the test suites to run.
   
       Populates the test suites to run. At least, it should pupulate the suites:
       "small", "nighlty" and "all"
   
       Return
       ------
   
       suites: A dictionary of suites
           The set of suites with its test_cases added.
       
       suites = KratosUnittest.KratosSuites
   
       # Create a test suit with the selected tests (Small tests):
       smallSuite = suites['small']
       smallSuite.addTest(TSprismTests('test_MembranePacth'))
       smallSuite.addTest(TSprismTests('test_BendingPacth'))
   
       # Create a test suit with the selected tests plus all small tests
       nightSuite = suites['nightly']
       nightSuite.addTests(smallSuite)
   
       # Create a test suit that contains all the tests:
       allSuite = suites['all']
       allSuite.addTests(
           KratosUnittest.TestLoader().loadTestsFromTestCases([
               TSprismTests
           ])
       )
   
       return suites
   
   if __name__ == '__main__':
       KratosUnittest.runTests(AssambleTestSuites())


The following corresponds with the Script that content the test examples:

   # Import Kratos
   from KratosMultiphysics import *
   from KratosMultiphysics.SolidMechanicsApplication import *
   from KratosMultiphysics.StructuralMechanicsApplication import *
   
   # Import KratosUnittest
   import KratosMultiphysics.KratosUnittest as KratosUnittest
   
   # Additional imports
   import constitutive_law_python_utility as constitutive_law_utils
   
   def GetFilePath(fileName):
       return os.path.dirname(__file__) + "/" + fileName
   
   class SprismTests(KratosUnittest.TestCase):
   
       def setUp(self):
           # Modelpart for the solid
           model_part = ModelPart("StructuralPart")
           model_part.AddNodalSolutionStepVariable(ALPHA_EAS)
           model_part.AddNodalSolutionStepVariable(DISPLACEMENT)
           model_part.AddNodalSolutionStepVariable(REACTION)
   
           # Initialize GiD  I/O
           input_file_name = GetFilePath("SPRISM3D6N/patch_test")
   
           # Reading the fluid part
           model_part_io_fluid = ModelPartIO(input_file_name)
           model_part_io_fluid.ReadModelPart(model_part)
           
           # Find neighbours if required
           sprism_neighbour_search = SprismNeighbours(model_part)
           sprism_neighbour_search.Execute()
   
           # Setting up the buffer size
           model_part.SetBufferSize(3)
   
           # Adding dofs
           for node in model_part.Nodes:
           node.AddDof(DISPLACEMENT_X, REACTION_X)
           node.AddDof(DISPLACEMENT_Y, REACTION_Y)
           node.AddDof(DISPLACEMENT_Z, REACTION_Z)
           
           # Set the constitutive law
           constitutive_law = constitutive_law_utils.ConstitutiveLawUtility(model_part, 3);
           constitutive_law.Initialize();
   
           max_iters = 30
   
           linear_solver = SkylineLUFactorizationSolver()
   
           # Create solver
           builder_and_solver = ResidualBasedBuilderAndSolver(linear_solver)
           mechanical_scheme = ResidualBasedStaticScheme()
           mechanical_convergence_criterion = ResidualCriteria(1e-4, 1e-4)
   
           self.mechanical_solver = ResidualBasedNewtonRaphsonStrategy(
               model_part,
               mechanical_scheme,
               linear_solver,
               mechanical_convergence_criterion,
               builder_and_solver,
               max_iters,
               False ,
               True,
               True)
   
           self.mechanical_solver.SetEchoLevel(0)
           self.mechanical_solver.Initialize()
   
           self.model_part = model_part
   
       def test_MembranePacth(self):
           step = 0
           time = 0.0
           Dt = 1.0
           final_time = 1.0
   
           # Add BC
           for node in self.model_part.Nodes:
               if (node.X >2.40000e-01 -1.0e-5) | (node.Y > 1.20000e-01 -1.0e-5) | (node.X < 1.0e-5) | (node.Y < 1.0e-5):
                   node.Fix(DISPLACEMENT_X)
                   node.SetSolutionStepValue(
                       DISPLACEMENT_X,
                       0,
                       1.0e-7 * (node.X + node.Y / 2))
                   node.Fix(DISPLACEMENT_Y)
                   node.SetSolutionStepValue(
                       DISPLACEMENT_Y,
                       0,
                       1.0e-7 * (node.Y + node.X / 2))
   
           while(time <= final_time):
   
               self.model_part.CloneTimeStep(time)
   
               time += Dt
               step += 1
   
               self.mechanical_solver.Solve()
   
           for node in self.model_part.Nodes:
               value = node.GetSolutionStepValue(DISPLACEMENT_X,0)
               self.assertAlmostEqual(value, 1.0e-7 * (node.X + node.Y / 2))
               value = node.GetSolutionStepValue(DISPLACEMENT_Y,0)
               self.assertAlmostEqual(value, 1.0e-7 * (node.Y + node.X / 2))
   
       def test_BendingPacth(self):
           step = 0
           time = 0.0
           Dt = 1.0
           final_time = 1.0
   
           # Add BC
           for node in self.model_part.Nodes:
               if (node.X >2.40000e-01 -1.0e-5) | (node.Y > 1.20000e-01 -1.0e-5) | (node.X < 1.0e-5) | (node.Y < 1.0e-5):
                   node.Fix(DISPLACEMENT_X)
                   node.SetSolutionStepValue(
                       DISPLACEMENT_X, 0,
                       -1.0e-7 * (node.Z - 0.0005) * (node.X + node.Y / 2))
                   node.Fix(DISPLACEMENT_Y)
                   node.SetSolutionStepValue(
                       DISPLACEMENT_Y, 0,
                       -1.0e-7 * (node.Z - 0.0005) * (node.Y + node.X / 2))
                   node.Fix(DISPLACEMENT_Z)
                   node.SetSolutionStepValue(
                       DISPLACEMENT_Z, 0,
                       0.5 * 1.0e-7 * (node.X ** 2 + node.X * node.Y + node.Y ** 2))
   
           while(time <= final_time):
   
               self.model_part.CloneTimeStep(time)
   
               time += Dt
               step += 1
               
               self.mechanical_solver.Solve()
   
           for node in self.model_part.Nodes:
               value = node.GetSolutionStepValue(DISPLACEMENT_X,0)
               self.assertAlmostEqual(
                   value,
                   -1.0e-7 * (node.Z - 0.0005) * (node.X + node.Y / 2))
               value = node.GetSolutionStepValue(DISPLACEMENT_Y,0)
               self.assertAlmostEqual(
                   value,
                   -1.0e-7 * (node.Z - 0.0005) * (node.Y + node.X / 2))
               value = node.GetSolutionStepValue(DISPLACEMENT_Z,0)
               self.assertAlmostEqual(value,
                   0.5 * 1.0e-7 * (node.X ** 2 + node.X * node.Y + node.Y **2 ))
       def tearDown(self):
           pass

You can download this example from here

Some common commands in Unittest

Personal tools
Categories