Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

110
Vistas
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 ?

about 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

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>
about 4 years ago · Santiago Trujillo Denunciar

0

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

about 4 years ago · Santiago Trujillo Denunciar

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.

about 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda