Fluent API for test doubles

There are several good frameworks out there to create test doubles with JavaScript. Jasmine  and Sinon provide test spies and stubs. JsMockito looks good too. However, creating your own API for test stubs is very easy. I've created mine as an exercise. It's a very naive implementation but it works. See the code:

  2. describe("a fluent API to create a test stub", function(){
  3. it("stubs out a method", function(){
  4. // the fluent API:
  5. function when(stub){
  6. return {
  7. thenReturn:function(arg1){
  8. stub.configureOutput(arg1);
  9. }
  10. };
  11. }
  12. function stub(actual){
  13. var expectedArgs,
  14. configuredOutput,
  15. isConfigured = false;
  16. actual.configureOutput = function(output){
  17. configuredOutput = output;
  18. isConfigured = true;
  19. }
  20. actual.someMethod = function(){
  21. if (isConfigured){
  22. if (expectedArgs[0] == arguments[0])
  23. return configuredOutput;
  24. return;
  25. }
  26. else
  27. expectedArgs = arguments;
  28. return actual;
  29. };
  30. return actual;
  31. }
  33. // the test confirming it works:
  34. var actualObject = {someMethod: function(a){return 1+a;}};
  35. var theStub = stub(actualObject);
  37. when(theStub.someMethod(2)).thenReturn(5);
  38. expect(theStub.someMethod(2)).toBe(5);
  39. });
  40. });

The implementation is not generalized to support any method or any number of parameters. I just wanted to play with the idea that I can invoke the stubbed method in the "when" statement and it doesn't execute anything apparently. It only executes the stubbed behavior once it's been configured.

It's very simple but it didn't come up to my mind when I implemented pyDoubles (now Doublex), which might have made the API even better.

pyDoubles 1.4 released

Thanks to Nestor Salceda, now pyDoubles do not raise errors on assertion failures, but just fails :-). Subtle difference but an important one. The other change is a new method alias, suggested by an user:


is now also:


Both methods are the same, just use whichever you fancy.

Thanks also to David Villa for some fine tuning and for packaging pyDoubles for Debian.

Thanks for your feedback, which makes this releases happen 🙂

pyDoubles 1.3 released

What's new in pyDoubles 1.3?

  1. times statement is also available in spies, not only mocks
  2. stubs ignoring arguments can live together with stubs defined with arguments
  3. a new matcher: obj_with_fields

1: This sintax is now possible:

  2. assert_that_method(spy_obj.some_method).was_called().times(2)
  3. or
  4. assert_that_method(spy_obj.some_method).was_called(
  5. ).with_args(SOME_VALUE).times(2)

2: The most precise matching condition will be used:

  2. when(spy_obj.some_method).then_return(SOME_VALUE)
  3. when(spy_obj.some_method).with_args(10
  4. ).then_return(OTHER_VALUE)

The two lines above inside a test would mean the objet will return OTHER_VALUE when the input parameter will be 10 and SOME_VALUE in any other case. In previous releases, it would return SOME_VALUE always because stubs ignoring arguments use to override any other stub definition.

3: obj_with_fields matcher:

  2. assert_that_method(spy_obj.some_method).was_called(
  3. ).with_args(obj_with_fields({'id': 20, 'name': 'Carlos'}))

Which means the object passed in as a parameter, should have fields id and name with those values.

pyDoubles 1.1 released

There you go another version of the pyDoubles framework, mock objects for Python and more 😉

What's new in this release?
Two minor bugfixes. You can see test cases and fixes here and here.
If you want to assert that a given object was passed in as a parameter, as exposed in this test, you have to declare the special methods "__eq__" (equals) and "__ne__" (not equals) in your objects. They are invoked when the framework asserts that the objects are the same. Otherwise, pyDoubles will see they are different instances of the object and will fail on the assertion.

On the other hand there are two new statements: