Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

152
Views
Unit testing with an Active Record based framework

I'm using a framework which based its ORM on the Active Record pattern. Every table I have in my database is bound to a model in my code.

I want to unit test these models, so I started by extracting every save() and update() call from models, so that changes are made only on objects, and they only get persisted once needed.

I don't know how I can apply this strategy in this case though. I have a Chat model, which a User is part of, and the User can add a ChatNote to the Chat.

Here's the current implementation :

// User.php
public function addChatNote($chatNoteContent, Chat $chat)
{
    $chatNote = new ChatNote();
    $chatNote->content = $chatNoteContent;
    $chatNote->save();

    $chat->note()->associate($chatNote);
    $chat->save();
}

Now to my eyes there are tons of problems here, but the save() calls are really ruining my chance to do proper unit testing here.

I thought about creating the ChatNote before using that method, but what class should be responsible for creating it ? I could also save it elsewhere, and save the Chat elsewhere but then is the User really responsible for anything else than associating the ChatNote to the Chat ? And where should the save() be made ?

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Indeed some classicist xunit testers also argue that any collaboration with external resources, such as a database or filesystem, should use doubles. Partly this is due to non-determinism risk, partly due to speed. While I think this is a useful guideline, I don't treat using doubles for external resources as an absolute rule. If talking to the resource is stable and fast enough for you then there's no reason not to do it in your unit tests.

(Martin Fowler)

You seem to be using Laravel. The framework provides out of the box some easy ways to integrate the database in your tests.

Antoher common practice is using a separate, in-memory database for testing. You can even create the schema from scratch (running all migrations) before each test. Just add this to your phpunit.xml:

<php>
    <env name="DB_CONNECTION" value="sqlite"/>
    <env name="DB_DATABASE" value=":memory:"/>
</php>
over 4 years ago · Santiago Trujillo Report

0

I think you should have a ChatNoteFactory that would return a ChatNote, passing a content through.

over 4 years ago · Santiago Trujillo Report

0

As @user3807702 said you can employ the AbstractFactory pattern or the Factory method to handle your Unit Testing of the application. E.g.

public function addChatNote($chatNoteContent, Chat $chat)
{
    $chatNote = $this->chatNoteFactory->newInstance();
    $chatNote->content = $chatNoteContent;
    $chatNote->save();

    $chat->note()->associate($chatNote);
    $chat->save();
}

This will help you to create a ChatNote mock that will not engage any database communication during testing.

$chatNote = $this->getMockBuilder(ChatNote::class)
                ->disableConstructor()
                ->setMethods(['save'])
                ->getMock();

$chatNoteFactoryMock = $this
    ->getMockBuilder(chatNoteFactoryMock::class)
    ->getMock();

$chatNoteFactoryMock
   ->method('newInstance')
   ->willReturn($chatNote);

//Pass the chat note factory mock to the User

The same you will do with the Chat object - pass its mock instead to addChatNote. So you will get pure Unit Tests w/o DB communication.

Still should say that save objects inside User could be considered as violation of the Separation of Concerns principle. The User should be bothered to store Chat and ChatNote into DB. Would be good to put the saves outside: you can do it explicit way or by using proxy objects, AOP frameworks, etc.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!