ts-mockito
ts-mockito copied to clipboard
Adding support for mocking interfaces
This commit adds support for mocking interfaces, like this:
interface Foo {
bar(value: string): string;
}
let mockedFoo: Foo = imock();
let foo: Foo = instance(mockedFoo);
when(mockedFoo.bar('a')).thenReturn('b');
Codecov Report
Merging #76 into master will decrease coverage by
1.34%. The diff coverage is83.33%.
@@ Coverage Diff @@
## master #76 +/- ##
==========================================
- Coverage 94.9% 93.56% -1.35%
==========================================
Files 34 34
Lines 609 653 +44
Branches 70 81 +11
==========================================
+ Hits 578 611 +33
- Misses 22 28 +6
- Partials 9 14 +5
| Impacted Files | Coverage Δ | |
|---|---|---|
| src/Spy.ts | 80.55% <100%> (ø) |
:arrow_up: |
| src/utils/MethodCallToStringConverter.ts | 100% <100%> (ø) |
:arrow_up: |
| src/MethodStubVerificator.ts | 100% <100%> (ø) |
:arrow_up: |
| src/MethodToStub.ts | 100% <100%> (ø) |
:arrow_up: |
| src/ts-mockito.ts | 92.75% <75%> (-3.97%) |
:arrow_down: |
| src/Mock.ts | 91.55% <81.39%> (-4.21%) |
:arrow_down: |
Continue to review full report at Codecov.
Legend - Click here to learn more
Δ = absolute <relative> (impact),ø = not affected,? = missing dataPowered by Codecov. Last update c1c7f69...a1baf00. Read the comment docs.
😮 @johanblumenberg this looks great! Interfaces mocking feature has been long awaited. I only got to think about imock function name and add readme.
Thanks for contributing!
@NagRock I added an exception if calling imock() with no Proxy support
This only supports stubbing methods, am I right? I also tried something like this some time ago but failed to differentiate between properties and method calls.
@Markus-Ende Yes, only stubbing methods. That's why I made a separate function, imock(), because it works slightly different.
But it's still quite useful to be able to automatically mock interfaces, even though you cannot mock properties on interfaces.
Hi, what is blocking this PR? Is there anything I can help with?
Looks useful. But I think there should be a type parameter for imock(). so the return types can be defined (just like when using mock()).
let mock = imock<Foo>(); // mock: Foo
let foo = instance(mock); // foo: Foo
EDIT: Sorry, I didn't see there already is a type parameter.
@NagRock Is there anything blocking this PR?
any update on this PR? will it be merged soon?
+1, when will it merged ?
+2 on merging
@NagRock any ideas when this will be merged and available?
@johanblumenberg maybe add usage examples to the readme as well?
Fixed a problem when retuning mock instances in thenResolve():
The problem is that the Promise.resolve() call will check if the given value is a promise, by checking if it has a function property named then. If so, it believes that the value is a promise, and will wait for it to resolve before returning.
A mock object will intersect all unknown properties and return a stub function, so it will look like a promise to the promise library.
(test "resolves with given mock value" in stubbing.method.spec.ts)
Added support for mocking both properties or methods on interfaces.
This will make all properties on the object to be stubbed as properties:
let mock: Foo = imock(MockPropertyPolicy.StubAsProperty);
when(mock.foo).thenReturn('xyz');
This will make all properties on the object to be stubbed as methods:
let mock: Foo = imock(MockPropertyPolicy.StubAsMethod);
when(mock.foo()).thenReturn('xyz');
For classes, the same behavior is kept. It will look at the class to decide which properties are methods and which are properties. The new policy applies to unknown properties and all properties on interfaces.
Added support for mocking interfaces containing both properties and methods. The default policy in the previous commit decides what happens with unknown properties. The type of a property can be set by setting up an expectation on the property.
let mock: Foo = imock();
when(mock.method()).thenReturn(1); // Here it is decided that 'method' is a method
when(mock.property).thenReturn(2); // Here it is decided that 'property' is a property
This must be done before the mock instance is used. If not, the default property policy is used to decide if the property is a property or a method.
@NagRock would you please consider merging this, this really blocks quite some use cases
Eagerly waiting for this to be merge
Is there an alternative way to mock an interface like this at this point? (without casting to any)
ping
Is there any updates on this, this is a blocker for us to use ts-mockito, specially because we have to implement interface to mock them. Can you please merge this soon, I've waiting for the this feature for so long, thank you for this awesome ts mocking lib.
@kouros51, @DonJayamanne, @cjanietz, @drenner-netspend, @kwolfy, @perransw, @Markus-Ende
I published a forked package, that contains the possibility to mock interfaces: https://www.npmjs.com/package/@johanblumenberg/ts-mockito
It has support for mocking methods and properties on interfaces.
Pushed another commit with updated README, describing imock()
@johanblumenberg thanks for that. This was very helpful.
@johanblumenberg
I tried your build, and I was having issues with mocking properties defined in interfaces. For example:
interface Foo {
someProperty: string;
}
describe('Tests', () => {
it('Should work', () => {
const fooMock: Foo = imock();
when(fooMock.someProperty).thenReturn('hello');
const foo = instance(foo);
expect(foo.name).to.equal('hello');
});
});
I rewrote this test from memory, I don't have the machine that ran this test, but you get the general gist of it. The explicit error was something like "could not reference 'add' property of undefined". I can't remember if the error occurs from the when clause or the expect clause.
Has anyone else seen this?
Hm... never mind. I tried to reproduce it locally with a much smaller sample, and it worked fine. The below code passes just fine:
import { imock, instance, when } from '@johanblumenberg/ts-mockito';
import { expect } from 'chai';
interface Foo {
someProperty: string;
}
describe('Test', () => {
it('Should work', () => {
const fooMock: Foo = imock();
when(fooMock.someProperty).thenReturn('hello!');
const foo = instance(fooMock);
expect(foo.someProperty).to.equal('hello!');
});
});
@NagRock Is this repository still maintained? This review was opened over a year ago, and despite being incredibly useful, hasn't been merged into master.
Essentially, I work on a project that heavily requires mocks, and we opted to go with ts-mockito over typemoq. Is it worth it to continue to wait for ts-mockito to merge this feature (among others in), or should we start looking at migrating to a new framework?
@aserra54 I published my fork as a package on npm: https://www.npmjs.com/package/@johanblumenberg/ts-mockito
Feel free to use it, or to suggest other PR's that I should add to it.
Unfortunately this PR doesn't support getters / setters mocking. Thats the reason why this is not merged.
So this will break some functionalities or we will have to remove getters / setters feature. This will also break existing projects that uses this functionality.
@NagRock Is this repository still maintained? This review was opened over a year ago, and despite being incredibly useful, hasn't been merged into master.
There is no good solution for interface mocking (or maybe there is but I dont have it). One will break current API, and this one will break getters / setters functionality.
Thanks for closing this PR, at least we have a resolution.