測試有關 if == int 的序列

有時候在程式中會有這樣的模式

if X == int_1:
    pass
elif X == int_2:
    pass
elif X == int_3:
    pass

X 與許多合法的整數去做比較。當我們忘記測試合法數值外的值的時候,突變測試會產生存活的突變。

備註

statements 的順序不是這麼的重要

Reproducer

$ pip install nose
$ pip install https://github.com/sixty-north/cosmic-ray/zipball/master

$ cosmic-ray run --test-runner nose --baseline=10 example.json selinux.py -- tests.py:Test_mode_from_int
$ cosmic-ray report example.json

job ID 3:Outcome.SURVIVED:selinux
command: cosmic-ray worker selinux replace_Eq_with_GtE 2 nose -- -v tests.py:Test_mode_from_int
--- mutation diff ---
--- a/example_08/selinux.py
+++ b/example_08/selinux.py
@@ -7,7 +7,7 @@
         retval += 'disabled'
     elif (int_mode == modes.SELINUX_ENFORCING):
         retval += 'enforcing'
-    elif (int_mode == modes.SELINUX_PERMISSIVE):
+    elif (int_mode >= modes.SELINUX_PERMISSIVE):
         retval += 'permissive'
     return retval

job ID 16:Outcome.SURVIVED:selinux
command: cosmic-ray worker selinux replace_Eq_with_LtE 0 nose -- -v tests.py:Test_mode_from_int
--- mutation diff ---
--- a/example_08/selinux.py
+++ b/example_08/selinux.py
@@ -3,7 +3,7 @@

 def mode_from_int(int_mode):
     retval = ''
-    if (int_mode == modes.SELINUX_DISABLED):
+    if (int_mode <= modes.SELINUX_DISABLED):
         retval += 'disabled'
     elif (int_mode == modes.SELINUX_ENFORCING):
         retval += 'enforcing'

job ID 17:Outcome.SURVIVED:selinux
command: cosmic-ray worker selinux replace_Eq_with_LtE 1 nose -- -v tests.py:Test_mode_from_int
--- mutation diff ---
--- a/example_08/selinux.py
+++ b/example_08/selinux.py
@@ -5,7 +5,7 @@
     retval = ''
     if (int_mode == modes.SELINUX_DISABLED):
         retval += 'disabled'
-    elif (int_mode == modes.SELINUX_ENFORCING):
+    elif (int_mode <= modes.SELINUX_ENFORCING):
         retval += 'enforcing'
     elif (int_mode == modes.SELINUX_PERMISSIVE):
         retval += 'permissive'

job ID 18:Outcome.SURVIVED:selinux
command: cosmic-ray worker selinux replace_Eq_with_LtE 2 nose -- -v tests.py:Test_mode_from_int
--- mutation diff ---
--- a/example_08/selinux.py
+++ b/example_08/selinux.py
@@ -7,7 +7,7 @@
         retval += 'disabled'
     elif (int_mode == modes.SELINUX_ENFORCING):
         retval += 'enforcing'
-    elif (int_mode == modes.SELINUX_PERMISSIVE):
+    elif (int_mode <= modes.SELINUX_PERMISSIVE):
         retval += 'permissive'
     return retval

total jobs: 24
complete: 24 (100.00%)
survival rate: 16.67%

殺死突變

要殺死所有的突變,我們需要測試合法範圍外的值:

$ cosmic-ray run --test-runner nose --baseline=10 example.json selinux.py -- tests.py:TestCompletely
$ cosmic-ray report example.json

程式碼

modes.py
SELINUX_DISABLED = 0
SELINUX_ENFORCING = 1
SELINUX_PERMISSIVE = 2
selinux.py
import modes

def mode_from_int(int_mode):
    retval = ""

    if int_mode == modes.SELINUX_DISABLED:
        retval += "disabled"
    elif int_mode == modes.SELINUX_ENFORCING:
        retval += "enforcing"
    elif int_mode == modes.SELINUX_PERMISSIVE:
        retval += "permissive"
# it doesn't matter if we have a trailing else clause or not
# uncomment this to experiment
#    else:
#        retval += "unknown"

    return retval
tests.py
import modes
import selinux
import unittest

class Test_mode_from_int(unittest.TestCase):
    def test_with_disabled(self):
        m = selinux.mode_from_int(modes.SELINUX_DISABLED)
        self.assertEqual(m, "disabled")

    def test_with_enforcing(self):
        m = selinux.mode_from_int(modes.SELINUX_ENFORCING)
        self.assertEqual(m, "enforcing")

    def test_with_permissive(self):
        m = selinux.mode_from_int(modes.SELINUX_PERMISSIVE)
        self.assertEqual(m, "permissive")


class TestCompletely(Test_mode_from_int):
    def test_with_values_outside_set(self):
        for mode in [-1, 9999]:
            m = selinux.mode_from_int(mode)
            self.assertEqual(m, "")

if __name__ == "__main__":
    unittest.main()