TelegramBots
TelegramBots copied to clipboard
sender field is protected and can't be mocked
Introduction
The documentation states that I can mock MessageSender
and assign it to the sender
field. However, the IDE informs me that this field is protected and can't be changed.
This code in the docs is incorrect I guess:
Question
How can I actually mock execute
method?
The following fragment of code shows what I need to mock(highlighted):
The AbilityBot constructor takes in a MessageSender. Pass the mocked sender and you should be good to go.
I’m not sure if it will actually work because AbilityBot does not have a constructor signature with MessageSender. Moreover, BaseAbilityBot creates DefaultSender.
I see. I don't like this, but I can see why the option to define this has been abandoned. The other workaround is to create a method (setSender) that takes in the sender and sets it in the bot class.
Yep, all this coupled logic frightens me, honestly :) I'd love this library to be less coupled but it will not be easy to fix it :) Interestengly is there any plans or disscussions to fix this?
The sender is done this way as a patch on top of DefaultAbsSender (which all bots inherit from). The "sending" capabilities and namely bot.execute
are all tied up together. AbilityBot came in to support an interface that is mockable (which is why you can mock something like a sender). The MessageSender
uses the bot under the hood anyways, but it's an interface that can be mocked.
When you use silent.send
, the propagation is:
SilentSender (MessageSender) -> DefaultSender (MessageSender) ->DefaultAbsSender (the bot itself)
You can mock all three, but mocking the bot will be alot of hard work mock patching what you need.
For people who use the silent
and sender
object, things can be easily tested once you replace the object with a mocked one. People who directly use bot.execute
and co will find a hard time doing so.
Okay, this sheds light on the issue. What is your way of mocking bot.execute or preventing it from connecting to actual Telegram servers(as stated in Wiki)?
Like anyway I have to replace a sender/silent object with mocked one BUT there’s no setter or public property field for this. As @addo37 says, the one workaround for now is creating a setter myself.
Yes, you'll need to create a method like
public void setSender(MessageSender sender) {
this.sender = sender;
}
And then on the test side:
@Before
public void setUp() {
db = offlineInstance("test");
YourBot bot = new YourBot(db); // <- Expose this constructor if you haven't, that is if you use the DB
sender = mock(MessageSender.class);
bot.setSender(sender);
}
Apply the same on the silent
object if you're using that too and would like to verify for testing.
Okay, great! Should we keep this issue open? I mean maybe the owner will consider implementing this feature «out of the box» in the future.
Issue could remain open. This is more of an inherent issue with the underlying infra. It should be reworked.
@rubenlagus Mind tagging this as enhancement?