Hi,
maybe I am missing something fundamental, because this seems like an obvious scenario I have a class Something with two methods Something>>askForName ^ UIManager default request: 'Name' Something>>name ^ self askForName , ' suffix' Now I want to mock out askForName, so I can run it automatically in tests... I've tried just stubbing it... SomethingTest>>testRenameStub Something stub askForName willReturn: 'new'. Something new name should be: 'new suffix' however it still opens the window to ask for the name, so the original method is being called. Right now I have to stub it with metalinks, which doesn't play well with some tools (hapao) SomethingTest>>testRenameMeta | link newName | link := MetaLink new metaObject: [ 'new' ]; control: #instead. (Something >> #askForName) ast link: link. [ newName := Something new name ] ensure: [ link uninstall ]. self assert: newName equals: 'new suffix' Thanks, Peter |
Hi Peter. You should stub instance instead of class: s := Something new. s stub askFor... 7 окт. 2017 г. 9:18 пользователь "Peter Uhnák" <[hidden email]> написал:
|
Thanks Denis, that did the trick. But I thought that I can also mock at the class level (at least it was shown in the docs). Peter On Sat, Oct 7, 2017 at 11:24 AM, Denis Kudriashov <[hidden email]> wrote:
|
Yes, but in that case you stub messages to the class itself. For your example it means:
Something askForName should be: 'new' 2017-10-20 13:58 GMT+02:00 Peter Uhnák <[hidden email]>:
|
Ah, right. I was expecting that other objects sending the message will receive the mocked result. Thanks, Peter On Fri, Oct 20, 2017 at 2:21 PM, Denis Kudriashov <[hidden email]> wrote:
|
In reply to this post by Denis Kudriashov
So you want to stub message to any instance of class. Right? Conceptually, in Mocketry/StateSpecs way, it should looks like:
But it will not really works. It will work only on instances which are already "stubbed". Making it really transparent will require crazy magic underhood. And I am not sure that it is really possible. Because generally it should cover existing instances and not just newly created during test. And for simple case: to automatically stub new instances their classes should be stubbed with special constructors. But system do not know what exact class side messages are constructors. So now you can just use simple mock which will be returned as simple stub from concrete constructor of your class:
I think it looks not not bad and no crazy magic is evolved. And of course you can replace mock with real instance if you want: some := Something new. some stub askForName: 'new'. Something stub new willReturn: some. 2017-10-20 14:21 GMT+02:00 Denis Kudriashov <[hidden email]>:
|
Denis Kudriashov wrote:
> So you want to stub message to *any* instance of class. Right? > > Conceptually, in Mocketry/StateSpecs way, it should looks like: > > (Instance of: Something) stub askForName willReturn: 'new'. > > or: > > (Kind of: Something) stub askForName willReturn: 'new'. > > > But it will not really works. It will work only on instances which are > already "stubbed". > Making it really transparent will require crazy magic underhood. And I > am not sure that it is really possible. > Because generally it should cover existing instances and not just newly > created during test. > And for simple case: to automatically stub new instances their classes > should be stubbed with special constructors. But system do not know what > exact class side messages are constructors. I had this problem. I tried something like (though not exactly w/ this code): Foo stub new will: [ :aMessage | | original | original := MockExpectedOriginalCall new executeFor: aMessage. original stub. ^ original ] but IIRC it failed on doing #stub inside will: block. > > So now you can just use simple mock which will be returned as simple > stub from concrete constructor of your class: > > some := Mock new. > > some stub askForName: 'new'. > > Something stub new willReturn: some. > > > I think it looks not not bad and no crazy magic is evolved. And of > course you can replace mock with real instance if you want: > > some := Something new. > > some stub askForName: 'new'. > > Something stub new willReturn: some. > > > > 2017-10-20 14:21 GMT+02:00 Denis Kudriashov <[hidden email] > <mailto:[hidden email]>>: > > Yes, but in that case you stub messages to the class itself. For > your example it means: > > Something stub askForName willReturn: 'new'. > > Something askForName should be: 'new' > > > > 2017-10-20 13:58 GMT+02:00 Peter Uhnák <[hidden email] > <mailto:[hidden email]>>: > > Thanks Denis, that did the trick. > > But I thought that I can also mock at the class level (at least > it was shown in the docs). > > Peter > > On Sat, Oct 7, 2017 at 11:24 AM, Denis Kudriashov > <[hidden email] <mailto:[hidden email]>> wrote: > > Hi Peter. > > You should stub instance instead of class: > s := Something new. > s stub askFor... > > 7 окт. 2017 г. 9:18 пользователь "Peter Uhnák" > <[hidden email] <mailto:[hidden email]>> написал: > > Hi, > > maybe I am missing something fundamental, because this > seems like an obvious scenario > > I have a class Something with two methods > > Something>>askForName > ^ UIManager default request: 'Name' > > Something>>name > ^ self askForName , ' suffix' > > Now I want to mock out askForName, so I can run it > automatically in tests... > > I've tried just stubbing it... > > SomethingTest>>testRenameStub > Something stub askForName willReturn: 'new'. > Something new name should be: 'new suffix' > > however it still opens the window to ask for the name, > so the original method is being called. > > Right now I have to stub it with metalinks, which > doesn't play well with some tools (hapao) > > SomethingTest>>testRenameMeta > | link newName | > link := MetaLink new > metaObject: [ 'new' ]; > control: #instead. > (Something >> #askForName) ast link: link. > [ newName := Something new name ] > ensure: [ link uninstall ]. > self assert: newName equals: 'new suffix' > > Thanks, > Peter > > > > |
Hi Herby.
2017-10-20 18:49 GMT+02:00 Herby Vojčík <[hidden email]>:
So the arguments of block in message #will: are expected to be arguments of stubbing message (not a full message instance). We can introduce new kind of expected action to automatically stub any result of message send:
With help of new subclass of MockExpectedOriginalMethodCall:
MockExpectedMessage>>willStubRealResult
And then you will be able specify expectations for all Foo instances: And you will be able assert any message which was sent to Foo instances:
I committed this code to the dev branch. But I am wondering that such kind of behaviour is really needed. Probably it is useful as you ask about it.
|
Denis Kudriashov wrote:
> Hi Herby. > > 2017-10-20 18:49 GMT+02:00 Herby Vojčík <[hidden email] > <mailto:[hidden email]>>: > > > I had this problem. I tried something like (though not exactly w/ > this code): > > Foo stub new will: [ :aMessage | > | original | > original := MockExpectedOriginalCall new executeFor: aMessage. > original stub. > ^ original ] > > but IIRC it failed on doing #stub inside will: block. > > > So the arguments of block in message #will: are expected to be arguments > of stubbing message (not a full message instance). > We can introduce new kind of expected action to automatically stub any > result of message send: > > Foo stub new willStubRealResult. Yeah, exactly, something like that is useful. > With help of new subclass of MockExpectedOriginalMethodCall: > > MockExpectedMethodResultStub>>executeFor: anOccurredMessage > > realMethodResult := super executeFor: anOccurredMessage. > > realMethodResult stub. > > ^realMethodResult. > > MockExpectedMessage>>willStubRealResult > > self will: MockExpectedMethodResultStub new Actually I tried this path myself but it failed badly during doing the sub-#stub with lots of "go one metalevel down" etc. calls in stack, so I gave up with "I don't understand this to make it work atm". Does your solution actually work? > And then you will be able specify expectations for all Foo instances: > > (Instance of: Foo) stub someMessage willReturn: #const As in, would `Foo new someMessage should be: #const`? In that case, great and thanks. > And you will be able assert any message which was sent to Foo instances: > > (Instance of: Foo) should receive someRequiredMessage which should > equal: #expectedValue > > I committed this code to the dev branch. But I am wondering that such > kind of behaviour is really needed. Probably it is useful as you ask > about it. Herby |
Hi
2017-10-24 20:07 GMT+02:00 Herby Vojčík <[hidden email]>: Denis Kudriashov wrote: Probably you not used superclass execution logic where right metalevel logic is implemented (notice that in my example I call "super executeFor:")
Yes for all questions. And new test is added for this feature
|
Free forum by Nabble | Edit this page |