Significance of testing
For a specific problem, through analysis and design, people finally write a program in programming language. If it passes the check of language interpreter (compiler) and can run, the next step is to try to make sure that it meets our requirements. This article is about how to confirm whether the program meets the requirements of users.
To meet the demand, in other words, the function is normal. The normal function can be confirmed from the following aspects:
- The defined function can return the correct result for all the correct parameters
- Write a program that produces the right output for all the right inputs
The method after quantification is to check the behavior, input and output of the program through a series of trial operation, and correct and improve if problems are found in the inspection. This is also the original intention of functional test and security test.
test case
The basic problem of testing is how to run the program, what data needs to be provided, in order to check the various behaviors and situations of the program to the maximum extent, and dig out the errors and defects in the program to the maximum extent. A set of data based on what test process is designed and what parameters are provided is called a test case. A test case is a quantifiable test process.
There are two ways to confirm test cases:
Black box testing
Is not to look at the code, directly to the use of test procedures. Black box is not discussed hereWhite box testing
The basis of white box testing is to see the internal structure (code) and possible execution path of the program, and select test cases according to the internal structure, so that the program can express as many different behaviors as possible in the experimental run. The basic idea of this approach is: if all possible execution paths (sequence, condition, while, for, nesting, etc.) can give correct results, then the correctness of the program can be guaranteed.
Test function function case
all kinds of languages will provide unit test libraries, Python is no exception. Python generally uses( https://docs.python.org/3/library/unittest.html).
Three functions to test:
def mysum(a, b): return a + b def mysubtraction(a, b): return a - b def is_evenNumbers(x): if (x % 2) == 0: return True else: return False
How to test a function:
import unittest import testbox.mymath as mymath class Test(unittest.TestCase): def setUp(self): print("The unit test function start.") def test_mysum(self): self.assertEqual(mymath.mysum(1, 2), 3, "mysum function have error!") def test_mysubtraction(self): self.assertEqual(mymath.mysubtraction(2, 1), 1, "mysubtraction function have error!") def test_is_evenNumbers(self): self.assertTrue(mymath.is_evenNumbers(2), "error") def test_is_evenNumbers2(self): self.assertFalse(mymath.is_evenNumbers(3), "error") def tearDown(self): print("The unit test end.") if __name__ == '__main__': unittest.main()
Output:
Testing started at 12:26 PM ... The unit test function start. The unit test end. The unit test function start. The unit test end. The unit test function start. The unit test end. The unit test function start. The unit test end.
Use of assert keyword
The function is actually the same as the above test function, except that assert can be used directly in the code. This keyword is also relatively remote, and there is no need to use it in any scene. I just used it to write a demo in order to make a case here.
def testasserts(a): assert a == 2, Exception("parameter a not is 2, so have a error.") if a == 2: print("function run.") print("OK. function end.") if __name__ == '__main__': testasserts(1) print("Program is end.")
Output:
Traceback (most recent call last): File "/Users/Mysticbinary/Document/code/personage/python/TestPython1/testbox/testadd.py", line 9, in <module> testasserts(1) File "/Users/Mysticbinary/Document/code/personage/python/TestPython1/testbox/testadd.py", line 2, in testasserts assert a == 2, Exception("parameter a not is 2, so have a error.") AssertionError: parameter a not is 2, so have a error.
Test function cases
The function test of class is the same as the function test, but there is only one trick: when testing and using a class, you need to instantiate the class first, and the operations of the instantiated class can be operated in setUp().
Classes to test:
class Library: allBook = ["php", "java"] def __init__(self): print("Library class create completion.") def savebook(self, bookname): self.allBook.append(bookname); return self.allBook def showbook(self): print(self.allBook) return self.allBook
Test the method of the class:
import unittest import testbox.myclass as myc class TestClass(unittest.TestCase): def setUp(self): print("The unit test class start.") self.library = myc.Library() self.newbook = "python" def test_savebook(self): self.assertIn(self.newbook, self.library.savebook(self.newbook), "errow 1") def test_showbook(self): self.assertIn(self.newbook, self.library.showbook(), "errow 2") def tearDown(self): print("The unit test end.") if __name__ == '__main__': unittest.main()
Output:
Testing started at 12:31 PM ... The unit test class start. Library class create completion. The unit test end. The unit test class start. Library class create completion. ['php', 'java', 'python'] The unit test end.
Security test case - SMS bombing
as I said before, both function test and security test have the same original intention, but the specific test methods are not the same. However, in some specific scenarios, using unit test method can also test some security problems, such as the problem of message bombing caused by exceeding the authority of test interface and repeated short message interface. I'm just going to give you an example of unit testing to do security testing, but for further research.
def send_message(phone): keys = phones_dict.keys() if phone not in keys: phones_dict[phone] = 0 else: if phones_dict[phone] < 10: # Execute the process of sending SMS phones_dict[phone] = (phones_dict[phone] + 1) print("Already sent{}Secondary SMS".format(phones_dict[phone])) return "success" else: print("Sorry.{}The mobile phone number has reached the upper limit of texting today. Please come back tomorrow.".format(phone)) return "error"
Test case for testing SMS function security:
def test_send_message(self): result = list() for i in range(0, 11): result.append(sms.send_message("13193388105")) print(result) self.assertNotIn("error", result, "send_message have error.")
Output:
Testing started at 9:48 PM ... The unit test function start. SMS has been sent once Text messages have been sent twice Three text messages have been sent Four text messages have been sent Five text messages have been sent Six text messages have been sent Seven text messages have been sent Eight text messages have been sent Nine text messages have been sent 10 text messages have been sent [None, 'success', 'success', 'success', 'success', 'success', 'success', 'success', 'success', 'success', 'success'] The unit test end.
__main? Global variable interpretation
in addition to unit testing, setting the module's main is also a test method, that is, calling the functions in each module separately. __Main is actually a global variable. The interpreter finds that if the module is imported, then main will be assigned the name of the module. If the module is started as the main module, then the interpreter will assign main to the string "main".
summary
- It is recommended not to bring debugging statements such as assert and print when the program goes online to avoid information disclosure.
- Unit tests are not only used for functional tests, but also for some specific security tests (specific scope includes those, I haven't studied them, and if there is a need, I may continue to study them in depth).
- Unit test assertions are very simple and easy to use. You can understand them at a glance. But knowing the usage of assertions doesn't mean that you can write test cases. Seeing the execution structure of program code is the key to writing tests. In a word, it's easy to write assertions, not easy to read code.