Question

I want to test my application

I have these two files (Not my real application but this presents the same problem).

File 1: testServer.py

import SocketServer
import SimpleHTTPServer

class ServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):

    def do_GET(self):
        f = self.wfile
        self.send_response(200)
        self.end_headers()
        f.write("ok")

def runServer(port):
    Handler = ServerHandler

    httpd = SocketServer.TCPServer(("", port), Handler)

    httpd.serve_forever()

if __name__ == "__main__":
    runServer(8000)

File 2: test_testServer.py

import testServer
from multiprocessing import Process
import httplib
import unittest


class Test(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.serverProcess = Process(target = testServer.runServer, args = (8000,))
        cls.serverProcess.daemon = True
        cls.serverProcess.start()

    @classmethod    
    def tearDownClass(cls):
        cls.serverProcess.terminate()


    def test_Server(self):
        conn = httplib.HTTPConnection("localhost", 8000)
        conn.request("GET", "")
        response = conn.getresponse().read()
        self.assertTrue(response, "ok")

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

So my goal is to start the server I coded in a process and then test its replies to different requests.

When I launch the test alone, it works perfectly fine:

 C:\Users\r.bunel\workspace\Sandbox>python test_testServer.py
 127.0.0.1 - - [23/Dec/2013 09:23:50] "GET / HTTP/1.1" 200 -

 ----------------------------------------------------------------------
 Ran 1 test in 1.009s

 OK

But if I start it as a part of my all test suite, by using unittest's discover, it doesn't work:

C:\Users\r.bunel\workspace\Sandbox>python -m unittest discover
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Python27\lib\multiprocessing\forking.py", line 380, in main
    prepare(preparation_data)
  File "C:\Python27\lib\multiprocessing\forking.py", line 488, in prepare
    assert main_name not in sys.modules, main_name
AssertionError: __main__
E
======================================================================
ERROR: test_Server (test_testServer.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\r.bunel\workspace\Sandbox\test_testServer.py", line 22, in test_Server
    conn.request("GET", "")
  File "C:\Python27\lib\httplib.py", line 973, in request
    self._send_request(method, url, body, headers)
  File "C:\Python27\lib\httplib.py", line 1007, in _send_request
    self.endheaders(body)
  File "C:\Python27\lib\httplib.py", line 969, in endheaders
    self._send_output(message_body)
  File "C:\Python27\lib\httplib.py", line 829, in _send_output
    self.send(msg)
  File "C:\Python27\lib\httplib.py", line 791, in send
    self.connect()
  File "C:\Python27\lib\httplib.py", line 772, in connect
    self.timeout, self.source_address)
  File "C:\Python27\lib\socket.py", line 571, in create_connection
    raise err
error: [Errno 10061] Aucune connexion nÆa pu Ûtre Útablie car lÆordinateur cible lÆa expressÚment refusÚe

----------------------------------------------------------------------
Ran 1 test in 2.009s

FAILED (errors=1)

So, my question is whether or not there is a reason for unittest to behave this way and what are my options to make these tests work inside unittest?

Was it helpful?

Solution 2

Ok, after realising with the help of @Alo Sarv that the problem lied in the multiprocessing module, I found a solution.

Here it is in case someone encounters the same problem:

file 1:testServer.py

    import SocketServer
import SimpleHTTPServer

class ServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):

    def do_GET(self):
        f = self.wfile
        self.send_response(200)
        self.end_headers()
        f.write("ok")

def runServer(port):
    Handler = ServerHandler

    httpd = SocketServer.TCPServer(("", port), Handler)

    httpd.serve_forever()

if __name__ == "__main__":
    runServer(8000)

file 2: test_testServer.py

    from testServer import ServerHandler
import SocketServer
from threading import Thread
import httplib
import unittest

class serverThread(Thread):

    def __init__(self, port):
        self.Handler = ServerHandler
        self.httpd = SocketServer.TCPServer(("", port), self.Handler)
        Thread.__init__(self)

    def run(self):
        self.httpd.serve_forever()


class Test(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.serverThread = serverThread(8000)
        cls.serverThread.daemon = True
        cls.serverThread.start()

    @classmethod    
    def tearDownClass(cls):
        cls.serverThread.httpd.__shutdown_request = True


    def test_Server(self):
        conn = httplib.HTTPConnection("localhost", 8000)
        conn.request("GET", "")
        response = conn.getresponse().read()
        self.assertTrue(response, "ok")

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

In short, the solution was to replace the use of multiprocessing by the use of threads. Then, adapting the server in order to be able to stop the thread properly (because thread can not be killed as easily as Process)

OTHER TIPS

Perhaps the unittest is trying to connect to the server before it has had time to start up properly in the second thread? Try adding time.sleep(1) after cls.serverProcess.start() in setupClass(cls) ?

@classmethod
def setUpClass(cls):
    cls.serverProcess = Process(target = testServer.runServer, args = (8000,))
    cls.serverProcess.daemon = True
    cls.serverProcess.start()
    time.sleep(1)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top