On 09:18 am, lacrima.ma...@gmail.com wrote: >Hi! > >I am learning to develop TDD way. I want to create a server that
Hooray! >understands PB protocol. Initially I thought it would be a good idea to >avoid real network connections in my tests, so I tried to use Yes, that's definitely what you want to do. >`proto_helpers.StringTransport`: StringTransport is frequently what you want in order to test a protocol implementation, so you're on the right track. Except... actually you're not implementing a protocol. You're *using* a protocol implementation that exists already and has its own unit tests. It would be better if you found a way to test your code without involving the PB protocol implementation or StringTransport. However, I admit that the tools for doing this with PB are almost non-existent. On the other hand, application code written for use with AMP is much more amenable to testing. Just something to think about. >---------- >import cStringIO >from twisted.spread import pb >from twisted.trial import unittest >from twisted.test import proto_helpers > >class Document(pb.Root): > > def remote_convert(self, props): > self.props = props > > >class DocTestCase(unittest.TestCase): > > def setUp(self): > > # set up server > self.doc = Document() > factory = pb.PBServerFactory(self.doc) > self.broker = factory.buildProtocol(('127.0.0.1', 0)) > tr = proto_helpers.StringTransport() > self.broker.makeConnection(tr) So far so good. You made a factory, got it to make you a protocol, and hooked the protocol up to a StringTransport you made. That's all good stuff. > > # this is what a client sends > self.props = {'name': 'MyDoc', > 'path': '/path/'} > > # prepare data > serialized_props = self.broker.serialize(self.props) > msg = ('message', 1, 'root', 'convert', 1, > ['tuple', serialized_props], ['dictionary']) > io = cStringIO.StringIO() > self.broker._encode(msg, io.write) > self.chunk = io.getvalue() This part isn't quite as good. `broker.serialize` is basically an implementation detail. `broker._encode` is *definitely* an implementation detail. The exact structure of the message isn't quite an implementation detail, but it's such a low-level detail that you really don't want to be thinking about it while writing tests for something like Document.remote_convert. Instead, you should probably use the PB client API (ie, PBClientFactory and what comes out of it) to interact with this server. Let the PB client implementation figure out what bytes to "send" to your server. > def test_convert(self): > # data arrived > self.broker.dataReceived(self.chunk) You'll definitely need to call dataReceived at some point. Perhaps more than once. So this is pretty good. > self.assertEqual(self.props, self.doc.props) >---------- > >However, `Document.remote_convert` is never executed so the test above >fails. After debugging I discovered that `Broker._encode` produces >different results depending on whether `self.broker.makeConnection(tr)` >is >called or not. I haven't bothered to look into what might be going on here, because I think you should forget about the `._encode` code and start using a client instead. The client is much more likely to produce the correct network traffic to exercise the code you want to exercise. The same goes for the two further tests below - which seem to differ only by a call to setPrefixLength, which should make absolutely no difference to this code when it is being used in practice, so the difference it makes in the tests is probably due to driving the code wrong, which problem will go away if you start using PBClientFactory etc. Hope this helps, Jean-Paul >And I created a test case that shows a difference. Here `test_convert1` >succeeds while `test_convert2` fails: >---------- >class DocTestCase(unittest.TestCase): > > def setUp(self): > self.doc = Document() > factory = pb.PBServerFactory(self.doc) > self.broker = factory.buildProtocol(('127.0.0.1', 0)) > > self.props = {'name': 'MyDoc', > 'path': '/path/'} > > serialized_props = self.broker.serialize(self.props) > self.msg = ('message', 1, 'root', 'convert', 1, > ['tuple', serialized_props], ['dictionary']) > > def test_convert1(self): > self.broker.currentDialect = 'pb' > self.broker.setPrefixLimit(64) > self.broker.transport = proto_helpers.StringTransport() > > io = cStringIO.StringIO() > self.broker._encode(self.msg, io.write) > self.broker.dataReceived(io.getvalue()) > > self.assertEqual(self.props, self.doc.props) > > def test_convert2(self): > self.tr = proto_helpers.StringTransport() > self.broker.makeConnection(self.tr) > > io = cStringIO.StringIO() > self.broker._encode(self.msg, io.write) > self.broker.dataReceived(io.getvalue()) > > self.assertEqual(self.props, self.doc.props) >---------- > >I wonder what causes this behavior and, in general, if >`StringTransport` is >suitable for testing PB protocol. > >Thanks in advance. For your convenience I attached files with these >test >cases. > >-- >with regards, >Maxim _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python