Refactor if X is not None

Objects of any type can be compared for not being None value however that leads to surviving mutations. None is a special value but in most practical cases it is equivalent to zero/empty value for the type.

Example

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

In example1.py we’re accepting None as default parameter value and correctly identified 3 test cases - when password is a string, when it is empty string and when it is None. There is one surviving mutant.

$ cosmic-ray run --test-runner nose --baseline=10 example.json example1.py -- test1.py:
$ cosmic-ray report example.json

job ID 5:Outcome.SURVIVED:example1
command: cosmic-ray worker example1 replace_IsNot_with_NotEq 0 nose -- -v test1.py
--- mutation diff ---
--- a/example_11/example1.py
+++ b/example_11/example1.py
@@ -1,7 +1,7 @@


 def reverse_password(password=None):
-    if (password is not None):
+    if (password != None):
         return password[::(- 1)]
     else:
         return ''

total jobs: 11
complete: 11 (100.00%)
survival rate: 9.09%

If we decide to remove None and accept an empty string instead then example2.py is reduced to one line and there are no surviving mutations. Also the number of mutations is significantly reduced.

$ cosmic-ray run --test-runner nose --baseline=10 example.json example2.py -- -v test2.py
$ cosmic-ray report example.json
job ID 1:Outcome.KILLED:example2
command: cosmic-ray worker example2 number_replacer 0 nose -- -v test2.py

job ID 2:Outcome.KILLED:example2
command: cosmic-ray worker example2 arithmetic_operator_deletion 0 nose -- -v test2.py

total jobs: 2
complete: 2 (100.00%)
survival rate: 0.00%

Source code

example1.py
def reverse_password(password = None):
    if password is not None:
        return password[::-1]
    else:
        return ''
test1.py
import example1 as example
import unittest

class TestReversePassword(unittest.TestCase):
    def test_non_empty_password(self):
        revpass = example.reverse_password('secret')
        self.assertEqual(revpass, 'terces')

    def test_empty_password(self):
        revpass = example.reverse_password('')
        self.assertEqual(revpass, '')

    def test_no_password_provided(self):
        revpass = example.reverse_password()
        self.assertEqual(revpass, '')

if __name__ == "__main__":
    unittest.main()
example2.py
def reverse_password(password = ''):
    return password[::-1]
test2.py
import example2 as example
import unittest

class TestReversePassword(unittest.TestCase):
    def test_non_empty_password(self):
        revpass = example.reverse_password('secret')
        self.assertEqual(revpass, 'terces')

    def test_empty_password(self):
        revpass = example.reverse_password('')
        self.assertEqual(revpass, '')

    def test_no_password_provided(self):
        revpass = example.reverse_password()
        self.assertEqual(revpass, '')

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