📜 ⬆️ ⬇️

Automated testing of bots for Telegram

It seems that time is a river that suddenly pereklinilo, and she decided to flow in a circle. It is this impression that appears at first glance when you see that bots in messengers have become popular again. But this impression is deceptive. A lot has changed - the power behind the bots, the ability for them to process multimedia information, the availability of information about users, the scope of coverage ... In general, this is clearly not a nostalgic trend, but a really useful technology that will continue to evolve.

Bots are getting harder, they take on many of the functions of other channels. For example, instead of making phone calls and listening to the recorded girl for half an hour, which tells you to go into tone mode and type a magic sequence of characters, the same can be done with the help of a bot. And it will be faster, more convenient, more flexible and cheaper.

For some personal project, I wanted to write a bot with a rather complex branching logic (for example, it could be a support or diagnostic system with deep nesting). At the same time, the graph of this logic has a huge number of ramifications. In general, it quickly became apparent that automated testing is indispensable - otherwise, I will definitely miss something. And how much I was surprised when I learned that there is simply no way to test the logic of bots!
')
Of course, you can register an additional bot for testing, but this is a variant of the curve and ugly. Appeal to external api during tests, a stub that will not allow anyone to communicate with the bot, a limit on the speed of sending messages once a second ... If you send a message once a second, a graph from some 60 vertices will be tested for more than a minute! And I'm not talking about the fact that we have no way to simulate the increased load on the bot, with which it rests on the limit of 30 messages per second ... In general, I realized that again I would have to do something different.

Two solutions to the problem


Superstructure


The first option with a huge speed of implementation is just an add-on over the most popular Node.JS library for the implementation of Telegram bots - node-telegram-bot-api . Made quite simple - an event handler is rewritten to send data, after which we process the data using our own method and send a manually generated request. It looks like this:

describe('Telegram Test', ()=> { const myBot = new TestBot(telegramBot); let testChat = 0; it('should greet Masha', () => { const telegramTest = new TelegramTest(telegramBot); testChat++; return telegramTest.sendUpdate(testChat, '/ping') .then((data)=> { if (data.text === 'pong') { return telegramTest.sendUpdate(testChat, '/start'); } throw new Error(`Wrong answer for ping! (was ${data.text})`); }) .then(data=> telegramTest.sendUpdate(testChat, data.keyboard[0][0].text)) .then((data)=> { if (data.text === 'Hello, Masha!') { return true; } throw new Error('Wrong greeting!'); }); }); }); 

You can find the bot that is used for this example on the library page, as well as this example itself - you do not want to give an extra copy-peysta.

Own server of API Telegram


The solution above is good for quickly testing some simple things and will cover most of the testing needs. However, what to do if we want to, say, test how our bot works under heavy load? In this case, the only logical way out is to implement your own Telegram API. It sounds pretty scary, but in fact we need a simple implementation that is compatible with current libraries for bots and allows us to send client requests. By the way, as a side feature - it turns out that we are making a full-fledged server with which you can work from any other technology stack - at least a python, at least C #, at least.

To make the long story short, I made this option. With him, testing the logic of the same bot looks like this:

  it('should greet Masha', function testFull() { this.slow(400); this.timeout(800); let serverConfig = {port: 9000}; let server = new TelegramServer(serverConfig); let token = 'sampleToken'; let client = server.getClient(token); let message = client.makeMessage('/start'); let telegramBot, testBot; return server.start() .then(()=> client.sendMessage(message)) .then(()=> { let botOptions = {polling: true, baseApiUrl: server.ApiURL}; telegramBot = new TelegramBot(token, botOptions); testBot = new TestBot(telegramBot); return client.getUpdates(); }) .then((updates)=> { console.log(colors.blue(`Client received messages: ${JSON.stringify(updates.result)}`)); if (updates.result.length !== 1) { throw new Error('updates queue should contain one message!'); } let keyboard = JSON.parse(updates.result[0].message.reply_markup).keyboard; message = client.makeMessage(keyboard[0][0].text); client.sendMessage(message); return client.getUpdates(); }) .then((updates)=> { console.log(colors.blue(`Client received messages: ${JSON.stringify(updates.result)}`)); if (updates.result.length !== 1) { throw new Error('updates queue should contain one message!'); } if (updates.result[0].message.text !== 'Hello, Masha!') { throw new Error('Wrong greeting message!'); } return true; }) }); 

That is, we are raising a server on our local port, further standardly setting up the bot to work with this server, and simply send it messages from bots and clients. The client object can be obtained directly from the server, or you can write your client - the server simply accepts messages in standard JSON format at a specific address.

Todo


Of course, there are a huge amount of all sorts of useful things that can be added. For example, now the message queue is stored simply in an array in RAM. Timeout emulation is not implemented, and only one client is supported at the same time (the server simply sends all messages to the client, who applied to it for data from a specific bot identified by a token). There is also support only for sending text messages. This is due to the fact that I currently only interested in the text.

The first project is nothing special to add, and the second is likely to develop in the direction of my personal needs. But I’m looking forward to the support of the open source community. MIT license, support for Node.js 4 and 6 (5 will also work, but it will not pass tests, because the bot used for the test is incompatible with Node 5. However, I already created a pull request for this), repositories are waiting for your pull requests from the code issued by the linter configuration included in the project. There are some tests too. Perhaps over time there will be support for bots for other instant messengers.

If you are interested in the theme of bots, then stay in touch. It will be interesting.

Links


  1. The first implementation (add-on node-telegram-bot-api);
  2. The second implementation (Telegram API emulation);
  3. A good article about dealing with restrictions on the speed of sending messages to go;
  4. Official limits on the speed of sending messages.

Source: https://habr.com/ru/post/322816/


All Articles