diff --git a/index.js b/index.js
index a632b6a..18ade3c 100644
--- a/index.js
+++ b/index.js
@@ -235,4 +235,4 @@ PythonShell.prototype.end = function (callback) {
     return this;
 };
 
-module.exports = PythonShell;
+module.exports = PythonShell;
\ No newline at end of file
diff --git a/test/python/conversation.py b/test/python/conversation.py
new file mode 100644
index 0000000..9b03a05
--- /dev/null
+++ b/test/python/conversation.py
@@ -0,0 +1,71 @@
+import sys, json, time
+
+ended = False
+
+def is_json(myjson):
+    try:
+        json_object = json.loads(myjson)
+    except ValueError, e:
+        return False
+    return True
+
+def makeError(reason):
+	ended = True
+	return {
+		'action': 'error',
+		'reason': reason
+	}
+
+def handleKnockKnock(obj):
+	response = {
+		'action': 'knockknockjoke'
+	};
+
+	message = obj['message'];
+	if (message == 'Knock, knock.'):
+		response['message'] = "Who's there?"
+		return response;
+
+	if (message == 'Orange.'):
+		response['message'] = "Orange who?"
+		return response;
+
+	if (message == "Orange you glad I didn't say, 'banana'?"):
+		response['message'] = "Ha ha."
+		ended = True
+		return response;
+
+	return makeError('Unrecognised knock-knock phase.')
+
+def handleAction(obj):
+	if 'action' not in obj:
+		return makeError("Unsupported input; expected 'action' key.")
+	
+	action = obj['action']
+	if action == 'knockknockjoke':
+		return handleKnockKnock(obj)
+
+	return makeError("Unrecognised action: {0}".format(action))
+
+def handleLine(line):
+	if not is_json(line):
+		return makeError('Malformed input could not be parsed as JSON: {0}'.format(line))
+
+	parsed = json.loads(line)
+
+	if type (parsed) != type({}):
+		return makeError('Malformed input: expected JSON object; received JSON primitive instead: {0}'.format(parsed))
+		
+	return handleAction(parsed)
+
+# simple JSON echo script
+while not ended:
+	line = sys.stdin.readline()
+	if not line:
+		break
+# for line in sys.stdin:
+
+	response = handleLine(line)
+
+	print json.dumps(response)
+	sys.stdout.flush()
\ No newline at end of file
diff --git a/test/test-python-shell.js b/test/test-python-shell.js
index 4898617..19479f6 100644
--- a/test/test-python-shell.js
+++ b/test/test-python-shell.js
@@ -1,5 +1,7 @@
 var should = require('should');
 var PythonShell = require('..');
+var util = require('util');
+var os = require("os");
 
 describe('PythonShell', function () {
 
@@ -63,32 +65,129 @@ describe('PythonShell', function () {
     });
 
     describe('.send(message)', function () {
-        it('should send string messages when mode is "text"', function (done) {
-            var pyshell = new PythonShell('echo_text.py', {
-                mode: 'text'
-            });
-            var output = '';
-            pyshell.stdout.on('data', function (data) {
-                output += ''+data;
+        context('text mode', function() {
+            it('should send string messages', function (done) {
+                var pyshell = new PythonShell('echo_text.py', {
+                    mode: 'text'
+                });
+                var output = '';
+                pyshell.stdout.on('data', function (data) {
+                    output += ''+data;
+                });
+                pyshell.send('hello').send('world').end(function (err) {
+                    if (err) return done(err);
+                    output.should.be.exactly('hello\nworld\n');
+                    done();
+                });
+            });  
+        })
+        context('JSON mode', function() {
+            it('should send JSON messages', function (done) {
+                var pyshell = new PythonShell('echo_json.py', {
+                    mode: 'json'
+                });
+                var output = '';
+                pyshell.stdout.on('data', function (data) {
+                    output += ''+data;
+                });
+                pyshell.send({ a: 'b' }).send(null).send([1, 2, 3]).end(function (err) {
+                    if (err) return done(err);
+                    output.should.be.exactly('{"a": "b"}\nnull\n[1, 2, 3]\n');
+                    done();
+                });
             });
-            pyshell.send('hello').send('world').end(function (err) {
-                if (err) return done(err);
-                output.should.be.exactly('hello\nworld\n');
-                done();
+            it('holds a conversation', function (done) {
+                var pyshell = new PythonShell('conversation.py', {
+                    mode: 'json'
+                });
+                var receivedMessages = [];
+
+                function makeKnockKnockMessage(message) {
+                    return {
+                        action: 'knockknockjoke',
+                        message: message
+                    };
+                }
+
+                var outgoingMessages = [
+                    "Knock, knock.",
+                    "Orange.",
+                    "Orange you glad I didn't say, 'banana'?"
+                ];
+
+                var incomingMessages = [
+                    "Who's there?",
+                    "Orange who?",
+                    "Ha ha."
+                ];
+
+                var makeKnockKnockReply = makeKnockKnockMessage;
+
+                function handleReply(reply) {
+                    switch(reply.message) {
+                        case incomingMessages[0]:
+                            pyshell.send(makeKnockKnockMessage(outgoingMessages[1]));
+                            break;
+                        case incomingMessages[1]:
+                            pyshell.send(makeKnockKnockMessage(outgoingMessages[2]));
+                            break;
+                        case incomingMessages[2]:
+                            endAndAssert();
+                            break;
+                    }
+                }
+
+                pyshell.on('message', function (message) {
+                    receivedMessages.push(message);
+
+                    switch(message.action) {
+                        case 'knockknockjoke':
+                            handleReply(message);
+                            break;
+                        default:
+                            done(util.format("Unexpected action: '%s'", data.action))
+                    }
+                });
+
+                pyshell.send(makeKnockKnockMessage(outgoingMessages[0]));
+
+                function endAndAssert() {
+                    pyshell.end(function (err) {
+                        if (err) {
+                            return done(err);
+                        }
+                        
+                        should(receivedMessages[0])
+                        .eql(makeKnockKnockReply(incomingMessages[0]),
+                            "Correct knock-knock reply received.");
+
+                        should(receivedMessages[1])
+                        .eql(makeKnockKnockReply(incomingMessages[1]),
+                            "Correct knock-knock reply received.");
+
+                        should(receivedMessages[2])
+                        .eql(makeKnockKnockReply(incomingMessages[2]),
+                            "Correct knock-knock reply received.");
+
+                        done();
+                    });
+                }
             });
         });
-        it('should send JSON messages when mode is "json"', function (done) {
-            var pyshell = new PythonShell('echo_json.py', {
-                mode: 'json'
-            });
-            var output = '';
-            pyshell.stdout.on('data', function (data) {
-                output += ''+data;
-            });
-            pyshell.send({ a: 'b' }).send(null).send([1, 2, 3]).end(function (err) {
-                if (err) return done(err);
-                output.should.be.exactly('{"a": "b"}\nnull\n[1, 2, 3]\n');
-                done();
+        context('binary mode', function() {
+            it('should write as-is', function (done) {
+                var pyshell = new PythonShell('echo_binary.py', {
+                    mode: 'binary'
+                });
+                var output = '';
+                pyshell.stdout.on('data', function (data) {
+                    output += ''+data;
+                });
+                pyshell.send(new Buffer('i am not a string')).end(function (err) {
+                    if (err) return done(err);
+                    output.should.be.exactly('i am not a string');
+                    done();
+                });
             });
         });
         it('should use a custom formatter', function (done) {
@@ -107,20 +206,6 @@ describe('PythonShell', function () {
                 done();
             });
         });
-        it('should write as-is when mode is "binary"', function (done) {
-            var pyshell = new PythonShell('echo_binary.py', {
-                mode: 'binary'
-            });
-            var output = '';
-            pyshell.stdout.on('data', function (data) {
-                output += ''+data;
-            });
-            pyshell.send(new Buffer('i am not a string')).end(function (err) {
-                if (err) return done(err);
-                output.should.be.exactly('i am not a string');
-                done();
-            });
-        });
     });
 
     describe('.receive(data)', function () {