2012-10-17 2 views
4

연결 해제 후 서버에 다시 연결하는 코드를 테스트하려고합니다. 이것은 테스트 밖에서는 완벽하게 작동하지만 테스트를 실행할 때 소켓이 단절되었음을 알리는 데 실패합니다.유닛 테스트에서 소켓 재사용 테스트를 죽이는 방법

import gevent.server 
from gevent import queue 


class TestServer(gevent.server.StreamServer): 

    def __init__(self, *args, **kwargs): 
     super(TestServer, self).__init__(*args, **kwargs) 
     self.sockets = {} 

    def handle(self, socket, address): 
     self.sockets[address] = (socket, queue.Queue()) 
     socket.sendall('testing the connection\r\n') 
     gevent.spawn(self.recv, address) 

    def recv(self, address): 
     socket = self.sockets[address][0] 
     queue = self.sockets[address][1] 
     print 'Connection accepted %s:%d' % address 
     try: 
      for data in socket.recv(1024): 
       queue.put(data) 
     except: 
      pass 

    def murder(self): 
     self.stop() 
     for sock in self.sockets.iteritems(): 
      print sock 
      sock[1][0].shutdown(socket.SHUT_RDWR) 
      sock[1][0].close() 
     self.sockets = {} 


def run_server(): 
    test_server = TestServer(('127.0.0.1', 10666)) 
    test_server.start() 
    return test_server 

을 그리고 내 테스트는 다음과 같습니다 :

내가 진짜 듣기 서버를 조롱하는 Gevent 스트림 서버를 사용하고 그것은 assert not client.socket_connected에 실패

def test_can_reconnect(self): 
    test_server = run_server() 
    client_config = {'host': '127.0.0.1', 'port': 10666} 
    client = Connection('test client', client_config, get_config()) 
    client.connect() 
    assert client.socket_connected 
    test_server.murder() 
    #time.sleep(4) #tried sleeping. no dice. 
    assert not client.socket_connected 
    assert client.server_disconnect 
    test_server = run_server() 
    client.reconnect() 
    assert client.socket_connected 

.

나는 recv 동안 "not data"를 감지한다. 그것이 None이라면, 다른 코드가 재 연결 여부를 결정할 수 있도록 일부 변수를 설정합니다 (user_disconnect 인 경우 다시 연결하지 마십시오). 이 동작은 작동하며 과거에는 항상 저에게 효과가있었습니다. 지금까지는 테스트를 해본 적이 없었습니다. 뭔가 소켓 연결 및 로컬 함수 범위 또는 뭔가 이상한 있습니까? 마치 서버를 멈춘 후에도 연결이 여전히 존재하는 것과 같습니다.

내가 테스트하는 데 노력하고있어 코드가 열려 : 당신이 테스트를 실행하면 https://github.com/kyleterry/tenyks.git

, 당신은 내가 실패 해결하기 위해 노력하고있어 하나를 볼 수 있습니다.

답변

2

실제 소켓을 사용하여 단위 테스트를 실행하는 것은 어려운 단계입니다. 서버 포트가 사용될 것이기 때문에 한 번에 하나의 테스트 세트 만 실행할 수 있고 소켓이 설치되고 찢어지면 속도가 느려지므로 까다로울 것입니다. 만약 이것이 실제로 단위 테스트라면 소켓을 테스트하고 싶지는 않습니다. 단지 소켓을 사용하는 코드 일뿐입니다.

소켓 호출을 조롱하면 조롱 한 코드에서 예외를 던질 수 있고 소켓을 사용하는 코드가 올바른 일을하는지 확인할 수 있습니다. 테스트중인 클래스가 옳은 일을하는지 확인하기 위해 실제 소켓이 필요하지 않습니다. 객체에서 소켓 호출을 래핑 할 수 있다면 위조 할 수 있습니다. 클래스를 생성 할 준비가되면 소켓 객체에 대한 참조를 전달하십시오.

제 제안은 sendall, recv 및 소켓에서 호출하는 모든 메소드를 지원하는 클래스에서 소켓 호출을 래핑하는 것입니다. 그런 다음 실제 Socket 클래스를 TestReconnectSocket (또는 무엇이든)로 교체하고 테스트를 실행할 수 있습니다.

파이썬 조롱 프레임 워크 인 mox을 살펴보십시오.

+0

포장은 고름입니다. 파이썬에는 [unittest.mock.patch'] (http://docs.python.org/dev/library/unittest.mock#id4)와 같은 외부 객체를 대체 할 수있는 좀 더 세련된 솔루션이 있습니다. –

0

막연한 반응이지만 내 즉각적인 반응은 recv() 호출이 블로킹하고 소켓을 활성화 상태로 유지하는 것입니다. 소켓을 비 블로킹으로 만들려고했는데 대신 닫으면 오류가 발생하는 것입니까?

0

이와 같은 소켓을 테스트 할 때 명심해야 할 것은 운영 체제가 사용 된 직후에 소켓을 다시 열지 않는 것입니다. 소켓 옵션을 설정하여 어쨌든 계속 사용하도록 할 수 있습니다. 소켓을 만든 직후에 소켓 옵션을 설정하십시오.

mysocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 

그러면 문제를 해결할 수 있기를 바랍니다. 어느 것이 문제를 일으키는 지에 따라 서버 및 클라이언트 측에서 모두 수행해야 할 수 있습니다.

+0

실제로 클라이언트가 매번 다른 포트를 사용하기 때문에 서버 소켓에서이 작업을 수행하면됩니다. – dail

0
  • shutdown(socket.SHUT_RDWR)으로 전화하면 problem with recv blocking처럼 보이지 않습니다.
  • 그러나, 당신은 gevent.socket.socket.recv를 사용하므로 gevent 버전을 확인하시기 바랍니다 block if the underlying file descriptor is closed로 인해 recv()에 문제가 여전히 협력 수율을하고주고 gevent.sleep()을해야 할 수도 있습니다
  • (버전 < v0.13.0)가 고객에게 recv() 통화를 종료 할 수 있습니다.
+0

어디에서 gevent.sleep()을 할 수 있습니까? – Kyle

+0

그리고 gevent == 0.13.8 – Kyle

+0

을 사용하면'TestServer.murder' 메소드의 끝에 넣을 수 있습니다. – dnozay

관련 문제