Python unittest on PyCharm sometimes passes without changing any code in SUT
Question: The problem is the first of it's kind which I have come across. I have a class
and the corresponding unit test. The test passes/fails randomly without any
change on the class under test. I mean I press **shift+F10** and immediately
press it again. One passes the other one fails.

This is the class (it looks kinda dirty, though. Forgive me)

    
    
    class XmlSerializer:
    
        def __init__(self, int_repr = 'int', str_repr = 'str'):
            """@int_repr: integer type representation (default: 'int')
            @str_repr : string type representation (default: 'str')"""
            self.xml_result = []
            self.__int_repr = int_repr
            self.__str_repr = str_repr
    
        def serialize(self, element):
            self.xml_result = []
            self.__recurse2(element, indent='')
            return ''.join(self.xml_result)
    
        def __recurse2(self, element, indent):
            if isinstance(element, int):
                self.xml_result += indent + '\t<' + self.__int_repr + '>' + str(element) + '</' + self.__int_repr + '>\n'
            if isinstance(element, str):
                self.xml_result += indent + '\t<' + self.__str_repr + '>' + str(element) + '</' + self.__str_repr + '>\n'
            elif type(element) in [type(list()), type(tuple()), type(dict())]:
                for el in element:
                    self.__recurse2(el, indent + '\t')
            else:
                try: # Attribute names are printed only here
                    attrs = vars(element)
                    self.xml_result += indent + '<' + element.__class__.__name__ + '>\n'
                    for attr in attrs:
                        self.xml_result += indent + '\t'  + '<'+ attr +'>\n'
                        self.__recurse2(attrs[attr], indent + '\t')
                        self.xml_result += indent + '\t'  + '</'+ attr +'>\n'
                    self.xml_result += indent + '</' + element.__class__.__name__ + '>\n'
                except Exception as ex:
                    pass
    

And here is the Test Class (the whole content of the file)

    
    
    import unittest
    from string_and_regex.xml_stuff import XmlSerializer
    
    
    class Person:
        def __init__(self):
            self.name = "Sam"
            self.age = 26
    
    
    class Group:
        def __init__(self):
            self.name = 'sample object'
            self.people = [Person(), Person()]
    
    
    group_serialized = '<Group>\n' \
                       '\t<name>\n' \
                       '\t\t<str>sample object</str>\n' \
                       '\t</name>\n' \
                       '\t<people>\n' \
                       '\t\t<Person>\n' \
                       '\t\t\t<name>\n' \
                       '\t\t\t\t<str>Sam</str>\n' \
                       '\t\t\t</name>\n' \
                       '\t\t\t<age>\n' \
                       '\t\t\t\t<int>26</int>\n' \
                       '\t\t\t</age>\n' \
                       '\t\t</Person>\n' \
                       '\t\t<Person>\n' \
                       '\t\t\t<name>\n' \
                       '\t\t\t\t<str>Sam</str>\n' \
                       '\t\t\t</name>\n' \
                       '\t\t\t<age>\n' \
                       '\t\t\t\t<int>26</int>\n' \
                       '\t\t\t</age>\n' \
                       '\t\t</Person>\n' \
                       '\t</people>\n' \
                        "</Group>\n"
    
    
    class TestXmlSerializer(unittest.TestCase):
        def test_serialize(self):
            serializer = XmlSerializer()
            xml_result = serializer.serialize(Group())
            self.assertEquals(group_serialized, xml_result)
    
    
    if __name__ == '__main__':
        unittest.main()
    

(Also forgive me for the test case I come up with, I know)


Answer: Dicts have no predictable iteration order. When you iterate over
`vars(element)`:

    
    
    attrs = vars(element)
    self.xml_result += indent + '<' + element.__class__.__name__ + '>\n'
    for attr in attrs:
    

Each run of your test will iterate in its own arbitrary order. This might be
fairly consistent, or randomized, or it might behave in pretty much any way,
depending on specifics of the interpreter implementation and settings. You're
probably on Python 3, in which string hash codes are randomized.

Don't depend on dict iteration order.

