TelegramBots icon indicating copy to clipboard operation
TelegramBots copied to clipboard

sender field is protected and can't be mocked

Open andriihorpenko opened this issue 5 years ago • 11 comments

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. image This code in the docs is incorrect I guess: image

Question

How can I actually mock execute method? The following fragment of code shows what I need to mock(highlighted): image

andriihorpenko avatar Feb 04 '20 23:02 andriihorpenko

The AbilityBot constructor takes in a MessageSender. Pass the mocked sender and you should be good to go.

addo47 avatar Feb 04 '20 23:02 addo47

I’m not sure if it will actually work because AbilityBot does not have a constructor signature with MessageSender. Moreover, BaseAbilityBot creates DefaultSender. CA0E67FA-0E5A-44D6-BE35-CFC71BE6E254

andriihorpenko avatar Feb 05 '20 01:02 andriihorpenko

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.

addo47 avatar Feb 05 '20 06:02 addo47

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?

kortov avatar Feb 05 '20 07:02 kortov

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.

addo47 avatar Feb 05 '20 08:02 addo47

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)?

andriihorpenko avatar Feb 05 '20 08:02 andriihorpenko

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.

andriihorpenko avatar Feb 05 '20 08:02 andriihorpenko

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);
}

addo47 avatar Feb 05 '20 09:02 addo47

Apply the same on the silent object if you're using that too and would like to verify for testing.

addo47 avatar Feb 05 '20 09:02 addo47

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.

andriihorpenko avatar Feb 05 '20 09:02 andriihorpenko

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?

addo47 avatar Feb 05 '20 17:02 addo47