Unit Testing – How to Test a Function That Uses Setters

mockingsettersunit testing

I'm using a repository pattern design and I've hit a stumbling block when writing a unit test for one of my methods. I'm fairly new to writing unit tests, so I would appreciate any help!

Let's say I have a method which creates a product and uses setters to set the data.

public function addProduct(array $data)
{
    $new = $this->repository->make(); // returns new Product object

    $new->setTitle($data['title']);
    $new->setPrice($data['price']);
    $new->setImage($data['image']);
    $new->setStock($data['stock']);

    return $this->repository->save($new); // returns bool
}

Now when I'm writing unit tests for this method, what should I actually be testing?

  1. Should I just check the return type and leave it at that?
  2. Should I mock the return of make() and ensure that all the setters were run?
  3. Should I mock just the repository and ensure that make() and save() were run?

Initially, I decided to go with all three options. However, my concern came from when I started option 2, writing tests to ensure that all the setters were run

Should the unit test really be concerned about whether all the setters ran? What happens if I add more fields? It seems like doing this would mean the tiniest change could result in the unit test failing when the method actually does as performed.


This is how I've wrote my unit test so far, but I'm really unsure about how strict it is

public function testAddProductAddsProductWithCorrectAttributes()
{
    $newMock = Mockery::make(ProductInterface::class)
                    ->shouldReceive('setTitle')
                    ->withArgs(['Test title'])
                    ->shouldReceive('setPrice')
                    ->withArgs([10.99])
                    ->shouldReceive('setImage')
                    ->withArgs(['/foobar.jpg'])
                    ->shouldReceive('setStock')
                    ->withArgs(['In Stock']);

    $repoMock = Mockery::make(RepositoryInterface::class)
                    ->shouldReceive('make')
                    ->andReturn($newMock)
                    ->shouldReceive('save')
                    ->withArgs([$newMock])
                    ->andReturn(true);

    $service = new Service($repoMock);

    $add = $service->addProduct([
        'title' => 'Test title',
        'price' => 10.99,
        'image' => '/foobar.jpg',
        'stock' => 'In Stock'
    ]);

    $this->assertTrue($add);
}

Best Answer

When testing a repository the essential thing to test is whether you can get out what you put in.

so... (excuse pseudo code)

$data = ..//whatever
addProduct(array $data)
$actual = getProduct(id)

Assert $actual == $data

This will obviously fail if the setters don't work. But doesn't explicitly test every setter

Related Topic