0

I have a python class that has methods to perform the CRUD operations via REST api:

class my_class():
 def get_obj(self,...) -> requests.Response:
 res = requests.get(...);
 return res;
 def create_obj(self, ...) -> requests.Response:
 res = requests.post(...);
 return res;
 def modify_obj(self, ...) -> requests.Response:
 res = requests.put(...);
 return res;
 def delete_obj(self, ...) -> requests.Response:
 res = requests.delete(...)
 return res;

I want to test these functionalities and to do that I can think of 3 ways:

  1. a single test that tests in cascade all the functionalities, something like:

    class test_myclass(unittest.TestCase):
     def setUp(self):
     self.api_class = my_class();
     def test_all(self):
     res = self.api_class.create_obj();
     self.assertTrue(res.ok);
     res = self.api_class.get_obj();
     self.assertTrue(res.ok);
     res = self.api_class.modify_obj();
     self.assertTrue(res.ok);
     res = self.api_class.modify_obj();
     self.assertTrue(res.ok);
    

    This has the advantage of being very compact and when the test succeed, everything is clean: all the created stuff is deleted. On the contrary, if one of the middle tests fails, then problems arise so maybe a tearDown() is needed.

  2. The second way is to test each functionality with a method:

    class test_myclass(unittest.TestCase):
     def setUp(self):
     self.api_class = my_class();
     def test_create(self):
     res = self.api_class.create_obj();
     if res.ok:
     self.api_class.delete_obj();
     self.assertTrue(res.ok);
     def test_get(self):
     res0 = self.api_class.create_obj();
     res = self.api_class.get_obj();
     if res0.ok:
     self.api_class.delete_obj();
     self.assertTrue(res.ok);
     def test_modify():
     res0 = self.api_class.create_obj();
     res = self.api_class.modify_obj();
     if res0.ok:
     self.api_class.delete_obj();
     self.assertTrue(res.ok);
     def test_delete
     self.api_class.create_obj();
     res = self.api_class.delete_obj();
     self.assertTrue(res.ok);
    

    This way is much more redundant but in my opinion tests are cleaner if a problem arises.

    1. The third way is to write a test class for each functionality: each one with a setUp and tearDown method:

      class test_myclass_create(unittest.TestCase):
       def tearDown(self):
       self.api_class.delete_obj();
       def test_create(self):
       res = self.api_class.create_obj();
       self.assertTrue(res.ok);
      class test_myclass_get(unittest.TestCase):
       def tearDown(self):
       self.api_class.delete_obj();
       def setUp(self):
       self.api_class.create_obj();
       def test_get(self):
       res = self.api_class.get_obj();
       self.assertTrue(res.ok);
      class test_myclass_modify(unittest.TestCase):
       def tearDown(self):
       self.api_class.delete_obj();
       def setUp(self):
       self.api_class.create_obj(); 
       def test_modify():
       res = self.api_class.modify_obj();
       self.assertTrue(res.ok);
      class test_myclass_get(unittest.TestCase):
       def tearDown(self):
       self.api_class.delete_obj();
       def setUp(self):
       self.api_class.create_obj(); 
       def test_delete:
       res = self.api_class.delete_obj();
       self.assertTrue(res.ok);
      

Does a best practice exist for such a case or is it just up to to the programmer?

asked Feb 17, 2020 at 14:40
0

1 Answer 1

2

The general best practice is to have one assertion per test. The idea driving this guideline is to limit the number of tests impacted by any given code change. There's nothing worse than changing one line of code only to discover 50 broken tests.

When a test breaks frequently people begin to think it is "flaky" or brittle. When people think this they tend to blame the test for every failure instead of the application.

Option #2 or #3 is the better way to go, depending on how much of the test setup is shared amongst the test cases and if there is a significant enough difference in the setup to warrant maintaining a whole separate test class.

Option #1 is definitely not preferable because one test has too many reasons to fail, making it harder to track down the defect. This will lead to people distrusting the test instead of the application. A good test seeds distrust of the application when the test fails, but reinforces trust in the application when the test passes.

answered Mar 4, 2020 at 22:51

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.