Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock/Stub constructor

I have the following code:

class Clients
  constructor : ->
    @clients = []

  createClient : (name)->

    client = new Client name
    @clients.push client

I am testing it with Jasmine BDD like this:

describe 'Test Constructor', ->

  it 'should create a client with the name foo', ->

    clients = new clients
    clients.createClient 'Foo'
    Client.should_have_been_called_with 'Foo'

  it 'should add Foo to clients', ->

    clients = new clients
    clients.createClient 'Foo'

    expect(clients.clients[0]).toEqual SomeStub

In my first test I want to check if the constructor is being called with the correct name. In my second I just want to confirm that whatever came out of new Client was added to the array.

I am using Jasmine BDD and it has a way to create spies/mocks/stubs but it seems it's not possible to test constructor. So I am looking into a way to test the constructor it would be nice if there is a way that I don't need an extra library but I am open to anything.

like image 624
Pickels Avatar asked Sep 25 '11 22:09

Pickels


People also ask

Can you mock a constructor?

0, we can now mock Java constructors with Mockito. This allows us to return a mock from every object construction for testing purposes. Similar to mocking static method calls with Mockito, we can define the scope of when to return a mock from a Java constructor for a particular Java class.

How do you mock a constructor method?

if your constructor is calling a method of its own class, you can fake the call using this API: // Create a mock for class MyClass (Foo is the method called in the constructor) Mock mock = MockManager. Mock<MyClass>(Constructor. NotMocked); // Faking the call to Foo mock.

How do you mock an Autowired constructor?

It uses field level annotations: @InjectMocks - Instantiates testing object instance and tries to inject fields annotated with @Mock or @Spy into private fields of testing object. @Mock - Creates mock instance of the field it annotates. @Spy - Creates spy for instance of annotated field.


2 Answers

It is possible to stub out constructors in Jasmine, the syntax is just a bit unexpected:

spy = spyOn(window, 'Clients');

In other words, you don't stub out the new method, you stub out the class name itself in the context where it lives, in this case window. You can then chain on a andReturn() to return a fake object of your choosing, or a andCallThrough() to call the real constructor.

See also: Spying on a constructor using Jasmine

like image 52
lambshaanxy Avatar answered Oct 19 '22 00:10

lambshaanxy


I think the best plan here is to pull out the creation of the new Client object to a separate method. This will allow you to test the Clients class in isolation and use mock Client objects.

I've whipped up some example code, but I haven't tested it with Jasmine. Hopefully you can get the gist of how it works:

class Clients
  constructor: (@clientFactory) ->
    @clients = []

  createClient : (name)->
    @clients.push @clientFactory.create name

clientFactory = (name) -> new Client name

describe 'Test Constructor', ->

  it 'should create a client with the name foo', ->
    mockClientFactory = (name) ->
    clients = new Clients mockClientFactory

    clients.createClient 'Foo'

    mockClientFactory.should_have_been_called_with 'Foo'

  it 'should add Foo to clients', ->
    someStub = {}
    mockClientFactory = (name) -> someStub
    clients = new Clients mockClientFactory

    clients.createClient 'Foo'

    expect(clients.clients[0]).toEqual someStub

The basic plan is to now use a separate function (clientFactory) to create new Client objects. This factory is then mocked in the tests allowing you to control exactly what is returned, and inspect that it has been called correctly.

like image 4
Karl Avatar answered Oct 19 '22 02:10

Karl