Hi,
I’m in the process of writing a series of classes to connect to an AOL
OSCAR server (the servers used by AIM), but I’m not quite sure how to
set up tests for the classes. Basically, what I have now is a test.rb
file that creates a new thread to run a mock OSCAR server. The test
code then connects to the mock server and does its thing. I then
check the log messages to see if the authentication and such have gone
as they should.
I’d like some way to use Test::Unit to run unit tests for this
project, but I’m not entirely sure how to do that, since I can’t test
individual methods unless there are sockets set up for transfer. Is
my mock server approach appropriate or is there some other way to do
unit testing for a protocol client?
I test my own network code similarly. The closest situation
I have to yours is probably my IRC client.
I do have one situation, testing higher level code, where I
run a mock IRC server in a separate thread. But that’s when
I’m testing “application” code that’s using my IRC client
class. For testing the IRC client itself, I (effectively)
run the client on a separate thread, and mock the server
with direct print() and gets() from the test functions.
Essentially:
SERVER_HOST = “localhost”
SERVER_PORT = 12345
def test_irccomm
# This is creating the "mock IRC server" on localhost
server = TCPServer.new(SERVER_PORT)
# Here I'm starting up the IRC client handler that I
# want to test, pointing it at my "mock server"...
# Note that my IRC client does its i/o in a background
# thread, which is why I said I "effectively" run
# the client on a separate thread. . . . If the client
# did blocking i/o in the foreground, then presumably
# we'd create a separate thread here in which to place
# the client. Because it's the mock server that I
# want to be in the "foreground" here...
cbh = TestIRCCallbackHandler.new
irc = IRCComm.new(SERVER_HOST, SERVER_PORT, cbh)
# Tell the client to initiate a connection.
# Note that the connect method doesn't wait for
# a result, it just makes the socket connection to
# the server, and issues the appropriate first
# registration handshake.
assert( irc.eof )
irc.connect(NICK1, USER, FULLNAME, USER_HOST)
assert( ! irc.eof )
# Now our "mock server" will accept the connection...
sv_client = server.accept
# ...and respond with some initial boilerplate:
send_connect_notice(sv_client)
# Now the mock server verifies the client sent the
# correct initial connection info:
assert_equal( "NICK #{NICK1}\r\n", sv_client.gets )
assert_equal( "USER #{USER} #{USER_HOST} #{SERVER_HOST} :#{FULLNAME}\r\n", sv_client.gets )
# The mock server responds with a problem:
sv_client.print ":#{SERVER_HOST} 433 * #{NICK1} :Nickname is already in use.\r\n"
# This is a hack for testing purposes... Added a waitio
# method in the client to force it to deal with the
# server response, before we continue...
irc.waitio
# The mock server verifies the client has responded
# with a "second choice" nickname...
assert_equal( "NICK #{NICK2}\r\n", sv_client.gets )
# . . . etc . . .
end
Anyway… hope this helps. I have several networking classes
I test with Test::Unit and they all seem to work out something
like the above, with the “mock server” in the foreground doing
the print() gets() assert() calls, and the client effectively
in the background.
Regards,
Bill
···
From: “Bill Atkins” dejaspam@batkins.com