Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lots of functions need unitary tests #29

Open
rjodon opened this issue Oct 14, 2020 · 8 comments
Open

Lots of functions need unitary tests #29

rjodon opened this issue Oct 14, 2020 · 8 comments
Assignees
Labels
enhancement New feature or request

Comments

@rjodon
Copy link
Collaborator

rjodon commented Oct 14, 2020

I think lots of functions are not so obvious to understand and could easily lead to bugs.
Writing unitary test for them within unittest framework would be a great idea for:

  • be sure that the code is bulletproof.
  • make refactoring and maintenance much easier
  • help to understand what the code does.

Example with this:

class Steel(SteelBase):

    def __init__(self, name, fy, fu, eu, E, v, p):
        super(Steel, self).__init__(name, fy, fu, eu, E, v, p)
        self.data = self._generate_data()

    def _generate_data(self):
        data_section = []
        line = """*Material, name={}
*Density
{},
*Elastic
{}, {}
*Plastic""".format(self.name, self.p, self.E['E'], self.v['v'])
        data_section.append(line)

        for i, j in zip(self.compression['f'], self.compression['e']):
            line = """{}, {}""".format(abs(i), abs(j))
            data_section.append(line)
        return '\n'.join(data_section)

If you take a month of holiday and I am in charge of the maintenance without knowing Abaqus, your part of the code, a small test case for this function will give me all the cards in my hand for fixing a bug. I will know exactly what is inside each variable and what to expect from the function.

@rjodon rjodon added the enhancement New feature or request label Oct 14, 2020
@rjodon
Copy link
Collaborator Author

rjodon commented Oct 14, 2020

Another remark, I would write like this (to test though):

    def _generate_data(self):
        data_section = ("*Material, name={}"
                        "*Density"
                        "{},"
                        "*Elastic"
                        "{}, {}"
                        "*Plastic").format(self.name, self.p, self.E['E'], self.v['v'])

        for i, j in zip(self.compression['f'], self.compression['e']):
            data_section = "{}\n{}, {}".format(data_section, abs(i), abs(j))
        return data_section

@tomvanmele
Copy link
Member

i think all these strings should be replaced by proper templates that are loaded from some kind of central location where they can be evaluated in a proper context. rather than being defined within the class...

@franaudo
Copy link
Contributor

@rjodon here I could use your help...never wrote unitary tests...

@rjodon
Copy link
Collaborator Author

rjodon commented Oct 15, 2020

I don't have the time today, but on Monday, I will add a few test to the repo, just to show you how it works.

@brgcode Any preferences for the tests? I am really not a fan of doctest it's too limited and makes docstrings a bit too long, I have never used pytest. I know unittest and find this framework very convenient if you need to mock instances etc...

@tomvanmele
Copy link
Member

COMPAS uses pytest but unittest is fine for me as well...

@rjodon
Copy link
Collaborator Author

rjodon commented Oct 15, 2020

OK, I will check how to use pytest in the compas repo, it's probably simpler for everybody if all our projects are following the same guidelines, uses the same tools etc...

@franaudo
Copy link
Contributor

I don't have the time today, but on Monday, I will add a few test to the repo, just to show you how it works.

@brgcode Any preferences for the tests? I am really not a fan of doctest it's too limited and makes docstrings a bit too long, I have never used pytest. I know unittest and find this framework very convenient if you need to mock instances etc...

great, thanks

@rjodon
Copy link
Collaborator Author

rjodon commented Oct 20, 2020

@franaudo I just committed a few test cases for a single function in material module that you find in abaqus.models.

I am discovering pytest framework. I am testing the method _generate_data.

In theory, the goal of unitary tests is to find out every cases that can happen with your function. In our case, you have a if/else and raise inside _generate_data. Each of this case needs to be tested. That's why there are 3 test cases. There are actually 4 tests, one of them is not a good test (the third one). Just simply because testing a not equal is not as strong as testing equal. (i.e. it's not because it's unequal that it's gonna be equal to what you implicitly expect).

Also, in theory, unitary test are testing a single and isolated function in a clean environment for each test, it's why I copy each time the function and create a new one for each case. I do want to start from a clean state. It's also to avoid including bugs in my test.

I am also often adding workflow tests. It helps when you need to refactor and want to keep a global behaviour.

Note: unittest framework seems better because of you can create testClass where you have a method SetUp and TearDown that are here to init and clean the common data to many tests. Then, each class methods is a test. However, I do prefer sticking to COMPAS choices.

Note: Most of unitary tests seems obvious and useless as you are testing really simple functions. When you refactor, they are life and time saving though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants