mirror of
				https://github.com/django/daphne.git
				synced 2025-10-30 23:37:25 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			121 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| Testing Consumers
 | |
| =================
 | |
| 
 | |
| When you want to write unit tests for your new Channels consumers, you'll
 | |
| realize that you can't use the standard Django test client to submit fake HTTP
 | |
| requests - instead, you'll need to submit fake Messages to your consumers,
 | |
| and inspect what Messages they send themselves.
 | |
| 
 | |
| We provide a ``TestCase`` subclass that sets all of this up for you,
 | |
| however, so you can easily write tests and check what your consumers are sending.
 | |
| 
 | |
| 
 | |
| ChannelTestCase
 | |
| ---------------
 | |
| 
 | |
| If your tests inherit from the ``channels.tests.ChannelTestCase`` base class,
 | |
| whenever you run tests your channel layer will be swapped out for a captive
 | |
| in-memory layer, meaning you don't need an external server running to run tests.
 | |
| 
 | |
| Moreover, you can inject messages onto this layer and inspect ones sent to it
 | |
| to help test your consumers.
 | |
| 
 | |
| To inject a message onto the layer, simply call ``Channel.send()`` inside
 | |
| any test method on a ``ChannelTestCase`` subclass, like so::
 | |
| 
 | |
|     from channels import Channel
 | |
|     from channels.tests import ChannelTestCase
 | |
| 
 | |
|     class MyTests(ChannelTestCase):
 | |
|         def test_a_thing(self):
 | |
|             # This goes onto an in-memory channel, not the real backend.
 | |
|             Channel("some-channel-name").send({"foo": "bar"})
 | |
| 
 | |
| To receive a message from the layer, you can use ``self.get_next_message(channel)``,
 | |
| which handles receiving the message and converting it into a Message object for
 | |
| you (if you want, you can call ``receive_many`` on the underlying channel layer,
 | |
| but you'll get back a raw dict and channel name, which is not what consumers want).
 | |
| 
 | |
| You can use this both to get Messages to send to consumers as their primary
 | |
| argument, as well as to get Messages from channels that consumers are supposed
 | |
| to send on to verify that they did.
 | |
| 
 | |
| You can even pass ``require=True`` to ``get_next_message`` to make the test
 | |
| fail if there is no message on the channel (by default, it will return you
 | |
| ``None`` instead).
 | |
| 
 | |
| Here's an extended example testing a consumer that's supposed to take a value
 | |
| and post the square of it to the ``"result"`` channel::
 | |
| 
 | |
| 
 | |
|     from channels import Channel
 | |
|     from channels.tests import ChannelTestCase
 | |
| 
 | |
|     class MyTests(ChannelTestCase):
 | |
|         def test_a_thing(self):
 | |
|             # Inject a message onto the channel to use in a consumer
 | |
|             Channel("input").send({"value": 33})
 | |
|             # Run the consumer with the new Message object
 | |
|             my_consumer(self.get_next_message("input", require=True))
 | |
|             # Verify there's a result and that it's accurate
 | |
|             result = self.get_next_message("result", require=True)
 | |
|             self.assertEqual(result['value'], 1089)
 | |
| 
 | |
| 
 | |
| Generic Consumers
 | |
| -----------------
 | |
| 
 | |
| You can use ``ChannelTestCase`` to test generic consumers as well. Just pass the message
 | |
| object from ``get_next_message`` to the constructor of the class. To test replies to a specific channel,
 | |
| use the ``reply_channel`` property on the ``Message`` object. For example::
 | |
| 
 | |
|     from channels import Channel
 | |
|     from channels.tests import ChannelTestCase
 | |
| 
 | |
|     from myapp.consumers import MyConsumer
 | |
| 
 | |
|     class MyTests(ChannelTestCase):
 | |
| 
 | |
|         def test_a_thing(self):
 | |
|             # Inject a message onto the channel to use in a consumer
 | |
|             Channel("input").send({"value": 33})
 | |
|             # Run the consumer with the new Message object
 | |
|             message = self.get_next_message("input", require=True)
 | |
|             MyConsumer(message)
 | |
|             # Verify there's a reply and that it's accurate
 | |
|             result = self.get_next_message(message.reply_channel.name, require=True)
 | |
|             self.assertEqual(result['value'], 1089)
 | |
| 
 | |
| 
 | |
| Groups
 | |
| ------
 | |
| 
 | |
| You can test Groups in the same way as Channels inside a ``ChannelTestCase``;
 | |
| the entire channel layer is flushed each time a test is run, so it's safe to
 | |
| do group adds and sends during a test. For example::
 | |
| 
 | |
|     from channels import Group
 | |
|     from channels.tests import ChannelTestCase
 | |
| 
 | |
|     class MyTests(ChannelTestCase):
 | |
|         def test_a_thing(self):
 | |
|             # Add a test channel to a test group
 | |
|             Group("test-group").add("test-channel")
 | |
|             # Send to the group
 | |
|             Group("test-group").send({"value": 42})
 | |
|             # Verify the message got into the destination channel
 | |
|             result = self.get_next_message("test-channel", require=True)
 | |
|             self.assertEqual(result['value'], 42)
 | |
| 
 | |
| 
 | |
| Multiple Channel Layers
 | |
| -----------------------
 | |
| 
 | |
| If you want to test code that uses multiple channel layers, specify the alias
 | |
| of the layers you want to mock as the ``test_channel_aliases`` attribute on
 | |
| the ``ChannelTestCase`` subclass; by default, only the ``default`` layer is
 | |
| mocked.
 | |
| 
 | |
| You can pass an ``alias`` argument to ``get_next_message`` and ``Channel``
 | |
| to use a different layer too.
 |