Use of if __name __ == '__ main__'. Why is the class not instantiated?

1

I have just been using Python and there are some things that I still confuse, my question is in this code:

import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

class PythonOrgSearch(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Firefox()

    def test_search_in_python_org(self):
        driver = self.driver
        driver.get("http://www.python.org")
        self.assertIn("Python", driver.title)
        elem = driver.find_element_by_name("q")
        elem.send_keys("pycon")
        elem.send_keys(Keys.RETURN)
        assert "No results found." not in driver.page_source


    def tearDown(self):
        self.driver.close()

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

Why in " if __name__ == "__main__": " he did not instantiate the class PythonOrgSearch and why putting the " unittest.main() " command executed the actions of the PythonOrgSearch class? This way you will not get confused? Can anyone explain why he did it this way?

    
asked by anonymous 12.09.2017 / 17:47

2 answers

3

In parts: Your block class with the class declaration creates the class yes - does not create an instance of the class. In Python this would be done using the class name as if it were a call to the function: PythonOrgSearch() . (Do not need the new keyword as in Java and JavaScript.)

What happens is that the unittest.TestCase class is special in the sense that the programmer does not need to instantiate the subclasses: when calling the function unittest.main() , the code there is in charge of using introspection to find the subclasses of TestCase and run the tests contained therein. In practice, they are barely used as "classes", except that you can create attributes in the setup method that will be available for "test" methods.

That is, this code file declares the class and that's it. What makes the tests run when calling unittest.main is the code itself that is there (in Python itself, just open the file and see - although it has lots of layers of extras to handle exceptions, etc ...). and this is done because it was an interesting way that they thought at the time to trigger the running of a test group - there is nothing special in the language in that regard. Without this code inside unittest.main() this file would simply do nothing.

Now the line that looks special if __name__ == "__main__": is a pattern that is widely used in Python based on the special variable __name__ : the language itself directs this variable to be equal to the name of the .py file running, except when this file is the main program running. (That is: you called python arquivo.py .) In this case, the value of this variable is " __main__ " (not "file"). So what this if does is define a block of code that will only be executed if the current file is called as the main Python program, but not when it is imported into another file , with command import .

The standard way of writing tests places the call of unittet.main on this block, which does what I described above. Apart from some special things in logging, and handling exceptions, doing what this unittest.main does is nothing out of this world - and a simplified way can be done in a few lines. A unittest minimum module could be:

class TestCase(object):
    def setUp(self):
        pass
    def tearDown(self):
        pass


def main():
   errors = []
   passed = 0
   failed = 0
   for cls in TestCase.__subclasses__():
       # acima teria que ser um pouco mais
       # sofisticado: o metodo __sublasses__
       # só  devolve as subclasses imediatas (mas não as  'netas')
       for attribute in cls.__dict__:
           if not attribute.startswith("test_"):
               continue
           if not callable cls.__dict__[attribute]:
               continue
           # A linha abaixo cria a instancia da classe em si.
           # Uma instância para cada método de teste:
           instance = cls()
           instance.setUp()
           try:
               # Execut o método de teste
               getattr(instance, attribute)()
           except Exception as err:
               message = "F"
               failed += 1
               erros.append(str(err))
           else:
               message = "."
               passed += 1
           finally:
               instance.tearDown() 
           print(message, end=" ", flush=True)

     print(f"\n\nFinished. Total tests: {failed + passed}, passed: {passed}, failed: {failed}")
    
13.09.2017 / 02:20
2

I see that you already have an answer with a good theoretical explanation, so I will respond without worrying about the functioning of TesteCase, based on the comments, I will try to induce the question author to understand the meaning of if __name__ == __main__

Let's create a script called foo.py

import bar
print ('Nome do modulo no arquivo foo.py:',__name__)

And another called bar.py

print ('Nome do modulo no arquivo bar.py:',__name__)

We run foo.py and see the result:

$ python foo.py
Nome do módulo, no arquivo bar.py:  bar
Nome do modulo no arquivo foo.py: __main__
  

See that in the call to foo the __name__ of the module in the scritp that was called is __main__ , as bar was called 'indirect', its name is the name of the script itself, you can see the result individually:

$ python bar.py 
Nome do módulo, no arquivo bar.py:  __main__

Now let's change the files so that bar calls foo , like this:

foo.py

print ('Nome do modulo no arquivo foo.py:',__name__)

bar.py

import foo
print ('Nome do módulo, no arquivo bar.py ', __name__)

Now see the result when we run foo:

$ python foo.py 
Nome do modulo no arquivo foo.py: __main__
  

The name of foo here is __main__ , because it is being called as the main module, now see when we call bar.

$ python bar.py 
Nome do modulo no arquivo foo.py: foo
Nome do módulo, no arquivo bar.py  __main__
  

When we call bar, it is now __main__ and as it calls foo , this happens to be, say secondary and loses the name __main__

    
13.09.2017 / 02:45