Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Different objects created using the same constructor function obtained using td.constructor share the same stubs #305

Closed
andsouto opened this issue Nov 24, 2017 · 4 comments

Comments

@andsouto
Copy link

I was expecting two different objects created using the same constructor function obtained using td.constructor will allow independent stubbing but I have found that latest td.when call replaces previous ones for every instance. Here is some example code of how to reproduce it:

var td = require('testdouble');

class Dog {
  bark() {}
}

FakeDog = td.constructor(Dog);

const dogA = new FakeDog();
const dogB = new FakeDog();

td.when(dogA.bark()).thenReturn('woof');
td.when(dogB.bark()).thenReturn('arf');

console.warn(dogA.bark()); // arf (but woof expected)
console.warn(dogB.bark()); // arf

Online example here: https://repl.it/repls/ExhaustedQuintessentialGelada

Documentation says:

any stubbings (or verifications) set up by the test on the FakeDog.prototype will also translate to the instances

but doesn't say anything about stubbing in one instance to be shared with every other instance so I suppose this is not expected.

@searls
Copy link
Member

searls commented Nov 24, 2017

Conceptually, what you're stubbing is the Dog.prototype.bark function, of which there is only one copy, so it follows to all instances. If you want to have two dogs act differently, you would need to fake the dog itself with:

const dogA = td.object(new Dog());
const dogB = td.object(new Dog());

I believe that a more accurate solution for what you want could be accomplished if withContext option is ever implemented. (#207) If it were you could fake the Dog constructor once and then separate the stubbings based on the bound instance:

td.when(FakeDog.prototype.bark(), {withContext: dogA}).thenReturn('woof');
td.when(FakeDog.prototype.bark(), {withContext: dogB}).thenReturn('arf');

Closing as if this were a duplicate of #207

@searls searls closed this as completed Nov 24, 2017
@searls
Copy link
Member

searls commented Nov 24, 2017

Oh, for a slightly uglier solution that still has you faking the Dog constructor as you are, you can also do this with thenDo and a branch:

td.when(FakeDog.prototype.bark()).thenDo(function () {
  return this == dogA ? 'woof' : 'arf'
})

Update: fixed method name to thenDo

@andsouto
Copy link
Author

The problem of using td.object is that constructor is executed. About the second option, what is thenCallFake? AFAIK that could be done using thenDo or am I missing something?

Just for reference, the solution I am using now is:

FakeDog1 = td.constructor(Dog);
FakeDog2 = td.constructor(Dog);

const dogA = new FakeDog1();
const dogB = new FakeDog2();

Once withContext is implemented it will probably be the best option. I still see a bit confusing that FakeDog.prototype.bark() behaves like dogA.bark() but rethinking it I suppose it has nothing to do with testdouble but with the way JS works. If it could be possible auto detecting the withContext depending on how the function is called when stubbing/verifying it will be really nice but not idea if that is possible.

@searls
Copy link
Member

searls commented Nov 24, 2017

blah, sorry thenDo is what you want. andCallFake was the name from Mockito and I still mixe it up

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants