216.73.216.141 TODAY : 58,391

PHP ์˜จ๋ผ์ธ ๊ฐ•์˜

 > 

PHP - ์ตœ์ƒ๊ธ‰

๐Ÿ“š PHP ์ตœ์ƒ๊ธ‰ - 6์ฃผ์ฐจ: ํ…Œ์ŠคํŠธ ์ž๋™ํ™” (๋‹จ์œ„/ํ†ตํ•ฉ/E2E ํ…Œ์ŠคํŠธ)- 02 ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ

๐Ÿ“š PHP ์ตœ์ƒ๊ธ‰ - 6์ฃผ์ฐจ: ํ…Œ์ŠคํŠธ ์ž๋™ํ™” (๋‹จ์œ„/ํ†ตํ•ฉ/E2E ํ…Œ์ŠคํŠธ)- 02 ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ

์ฃผ์š” ํ”„๋กœ๊ทธ๋žจ ์ŠคํŽ™

  • ํ‰์ : 10.0
  • ๋ผ์ด์„ ์Šค: free
  • ์šด์˜์ฒด์ œ:
  • ํŒŒ์ผ ํฌ๊ธฐ: 0

ํ”ผ๋“œ๋ฐฑ ๋ฐ ๋‹ค์šด๋กœ๋“œ

  • ์‚ฌ์šฉ์ž ํ‰์ : 10.0
  • ๋‹ค์šด๋กœ๋“œ ์ˆ˜: 0
  • ์กฐํšŒ์ˆ˜: 1

์ œ์กฐ์‚ฌ ๋ฐ ๋“ฑ๋ก ์ •๋ณด

  • ์ œ์ž‘์‚ฌ: LUZENSOFT
  • ๋“ฑ๋ก์ผ: 2025-10-20 13:28:58
  •  

- ์„ค๋ช…

ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์˜ ์ดํ•ด์™€ ์ค‘์š”์„ฑ

uploadImage

#์†Œํ”„ํŠธ์›จ์–ด #๊ฐœ๋ฐœ์—์„œ #ํ…Œ์ŠคํŠธ๋Š” ์—ฌ๋Ÿฌ ๊ณ„์ธต์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ง€๋‚œ๋ฒˆ #๋‹จ์œ„ #ํ…Œ์ŠคํŠธ(#Unit_Test)์— ์ด์–ด ์ด๋ฒˆ์—๋Š” **#ํ†ตํ•ฉ #ํ…Œ์ŠคํŠธ(#Integration_Test)**์— ๋Œ€ํ•ด ๋‹ค๋ฃฐ ๊ฑฐ์˜ˆ์š”. #ํ†ตํ•ฉ #ํ…Œ์ŠคํŠธ๋Š” ์—ฌ๋Ÿฌ #๋ชจ๋“ˆ(#Module)์ด๋‚˜ #์ปดํฌ๋„ŒํŠธ(#Component)๊ฐ€ ์„œ๋กœ ์–ด๋–ป๊ฒŒ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์ด๋“ค์ด ํ•จ๊ป˜ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ๊ฒ€์ฆํ•˜๋Š” ๊ณผ์ •์ด์—์š”.

#๋‹จ์œ„ #ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐœ๋ณ„ ์ฝ”๋“œ์˜ ์ •ํ™•์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค๋ฉด, #ํ†ตํ•ฉ #ํ…Œ์ŠคํŠธ๋Š” ์ด๋“ค์ด ๊ฒฐํ•ฉ๋˜์—ˆ์„ ๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ, ์˜ˆ๋ฅผ ๋“ค์–ด #์ธํ„ฐํŽ˜์ด์Šค(#Interface) ๋ถˆ์ผ์น˜, #๋ฐ์ดํ„ฐ #์ „๋‹ฌ ์˜ค๋ฅ˜ ๋“ฑ์„ ์ฐพ์•„๋‚ด์š”. ์ด๋Š” ์‹ค์ œ ์‚ฌ์šฉ์ž ์‹œ๋‚˜๋ฆฌ์˜ค์™€ ๋” ๊ฐ€๊นŒ์šด ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธํ•จ์œผ๋กœ์จ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฒฌ๊ณ ์„ฑ์„ ํ™•๋ณดํ•˜๋Š” ๋ฐ ๋งค์šฐ ์ค‘์š”ํ•ด์š”.



ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ์„ค์ •

uploadImage

#PHP์—์„œ #ํ†ตํ•ฉ #ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ๋„ #PHPUnit์„ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ์‹ค์ œ #๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋‚˜ #์™ธ๋ถ€ #์„œ๋น„์Šค์™€์˜ ์—ฐ๋™์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ช‡ ๊ฐ€์ง€ ์ถ”๊ฐ€์ ์ธ ์„ค์ •์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์–ด์š”.


1. ํ…Œ์ŠคํŠธ ์ „์šฉ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฐ ํ™˜๊ฒฝ


  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค: #ํ†ตํ•ฉ #ํ…Œ์ŠคํŠธ๋Š” ์‹ค์ œ #DB์— ์ ‘๊ทผํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์œผ๋ฏ€๋กœ, ๊ฐœ๋ฐœ์šฉ #DB์™€๋Š” ๋ณ„๊ฐœ์˜ ํ…Œ์ŠคํŠธ ์ „์šฉ #๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์•„์š”. ๊ฐ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์ „์— #DB๋ฅผ ์ดˆ๊ธฐํ™”(#Migration, #Seeding)ํ•˜์—ฌ ์ผ๊ด€๋œ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ด์š”.

  • ํ™˜๊ฒฝ ๋ณ€์ˆ˜: #PHPUnit ์„ค์ • ํŒŒ์ผ(phpunit.xml)์—์„œ #ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์— ๋งž๋Š” #ํ™˜๊ฒฝ #๋ณ€์ˆ˜(#Environment_Variable)๋ฅผ ์„ค์ •ํ•˜๊ฑฐ๋‚˜, ๋ณ„๋„์˜ ์„ค์ • ํŒŒ์ผ์„ ๋กœ๋“œํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์–ด์š”.


2. ํ…Œ์ŠคํŠธ ํ—ฌํผ ๋ฐ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ํŒŒ์ผ


  • phpunit.xml์— ์ง€์ •๋œ bootstrap ํŒŒ์ผ์—์„œ #ํ…Œ์ŠคํŠธ #ํ™˜๊ฒฝ์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋กœ์ง์„ ๊ตฌํ˜„ํ•ด์š”. ์˜ˆ๋ฅผ ๋“ค์–ด, #DI #์ปจํ…Œ์ด๋„ˆ(#Dependency_Injection_Container) ์„ค์ •, #DB #์—ฐ๊ฒฐ, #ORM ์ดˆ๊ธฐํ™” ๋“ฑ์„ ์ˆ˜ํ–‰ํ•ด์š”.

  • tests/bootstrap.php ์˜ˆ์‹œ:

    PHP

    <?php
    require dirname(__DIR__) . '/vendor/autoload.php';
    
    // ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ๋กœ๋“œ (์˜ˆ: .env.testing)
    if (file_exists(dirname(__DIR__) . '/.env.testing')) {
        $dotenv = DotenvDotenv::createImmutable(dirname(__DIR__), '.env.testing');
        $dotenv->load();
    }
    
    // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์„ค์ • (์˜ˆ: PDO)
    // $pdo = new PDO(...) 
    // DB ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐ ์‹œ๋”ฉ
    // ...
    


ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ์›์น™ ๋ฐ ์‹ค์ œ ์˜ˆ์‹œ

uploadImage

#๋‹จ์œ„ #ํ…Œ์ŠคํŠธ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ #PHPUnit์˜ TestCase๋ฅผ ์ƒ์†๋ฐ›์ง€๋งŒ, ํ…Œ์ŠคํŠธ์˜ ์ดˆ์ ์ด ๋‹ฌ๋ผ์ ธ์š”.


1. ํ…Œ์ŠคํŠธ ๋Œ€์ƒ


  • #์ปจํŠธ๋กค๋Ÿฌ(#Controller)์™€ #์„œ๋น„์Šค(#Service), #์„œ๋น„์Šค์™€ #๋ฆฌํฌ์ง€ํ† ๋ฆฌ(#Repository), #๋ฆฌํฌ์ง€ํ† ๋ฆฌ์™€ #DB ๋“ฑ ์—ฌ๋Ÿฌ ๊ณ„์ธต์ด ํ•จ๊ป˜ ๋™์ž‘ํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ํ…Œ์ŠคํŠธํ•ด์š”.

  • ์™ธ๋ถ€ #API์™€์˜ ์—ฐ๋™, #ํŒŒ์ผ #์‹œ์Šคํ…œ(#File_System) ์ ‘๊ทผ ๋“ฑ๋„ ํฌํ•จ๋  ์ˆ˜ ์žˆ์–ด์š”.


2. Fixtures (ํ…Œ์ŠคํŠธ ๊ณ ์ •๊ฐ’)


#ํ†ตํ•ฉ #ํ…Œ์ŠคํŠธ๋Š” ์ข…์ข… ํŠน์ • #์ดˆ๊ธฐ #๋ฐ์ดํ„ฐ #์ƒํƒœ๋ฅผ ์š”๊ตฌํ•ด์š”. ์ด๋ฅผ ์œ„ํ•ด #Fixtures๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์ „์— #DB์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฏธ๋ฆฌ ๋„ฃ์–ด๋‘๊ณ , ํ…Œ์ŠคํŠธ ์™„๋ฃŒ ํ›„ ์ •๋ฆฌํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์ณ์š”.

  • setUp() ๋ฉ”์„œ๋“œ์—์„œ #Fixtures๋ฅผ ๋กœ๋“œํ•˜๊ณ , tearDown() ๋ฉ”์„œ๋“œ์—์„œ ์ •๋ฆฌํ•ด์š”.

  • ์˜ˆ์‹œ: ๊ฒŒ์‹œํŒ #์„œ๋น„์Šค์˜ ๊ธ€ ์ƒ์„ฑ ๋ฐ ์กฐํšŒ ํ…Œ์ŠคํŠธ


3. ์‹ค์ œ ์˜ˆ์‹œ: ๊ฒŒ์‹œ๋ฌผ ๊ด€๋ฆฌ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ


๊ฐ„๋‹จํ•œ ๊ฒŒ์‹œ๋ฌผ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์„ ๊ฐ€์ •ํ•˜๊ณ , ๊ฒŒ์‹œ๋ฌผ์„ ์ƒ์„ฑํ•˜๊ณ  ์กฐํšŒํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋Œ€ํ•œ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•ด ๋ณผ๊ฒŒ์š”.

src/PostRepository.php

PHP

<?php
// PostRepository.php (๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์—ฐ๋™)
class PostRepository {
    private PDO $pdo;

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }

    public function create(string $title, string $content): int {
        $stmt = $this->pdo->prepare("INSERT INTO posts (title, content) VALUES (:title, :content)");
        $stmt->execute([':title' => $title, ':content' => $content]);
        return (int)$this->pdo->lastInsertId();
    }

    public function find(int $id): ?array {
        $stmt = $this->pdo->prepare("SELECT * FROM posts WHERE id = :id");
        $stmt->execute([':id' => $id]);
        $post = $stmt->fetch(PDO::FETCH_ASSOC);
        return $post ?: null;
    }
}

tests/Integration/PostManagementTest.php

PHP

<?php
use PHPUnitFrameworkTestCase;

// ํ…Œ์ŠคํŠธ ์ „์šฉ PDO ๊ฐ์ฒด (์‹ค์ œ DB ์—ฐ๊ฒฐ)
class TestDatabase
{
    private static ?PDO $pdo = null;

    public static function getConnection(): PDO
    {
        if (self::$pdo === null) {
            // .env.testing ๋“ฑ์—์„œ DB_DSN, DB_USER, DB_PASS ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
            $dsn = $_ENV['DB_DSN'] ?? 'sqlite::memory:'; 
            $user = $_ENV['DB_USER'] ?? null;
            $pass = $_ENV['DB_PASS'] ?? null;
            self::$pdo = new PDO($dsn, $user, $pass);
            self::$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            self::$pdo->exec("CREATE TABLE IF NOT EXISTS posts (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title VARCHAR(255) NOT NULL,
                content TEXT NOT NULL
            )");
        }
        return self::$pdo;
    }

    public static function resetDatabase(): void
    {
        $pdo = self::getConnection();
        $pdo->exec("DELETE FROM posts");
        $pdo->exec("DELETE FROM sqlite_sequence WHERE name='posts'"); // SQLite AUTOINCREMENT ์žฌ์„ค์ •
    }
}

class PostManagementTest extends TestCase
{
    private PostRepository $postRepository;

    protected function setUp(): void
    {
        parent::setUp();
        TestDatabase::resetDatabase(); // ๊ฐ ํ…Œ์ŠคํŠธ ์ „์— DB ์ดˆ๊ธฐํ™”
        $this->postRepository = new PostRepository(TestDatabase::getConnection());
    }

    public function testPostCreationAndRetrieval(): void
    {
        // Arrange
        $title = "์ฒซ ๋ฒˆ์งธ ๊ฒŒ์‹œ๊ธ€";
        $content = "๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.";

        // Act - ๊ฒŒ์‹œ๋ฌผ ์ƒ์„ฑ ๋ฐ ์กฐํšŒ (PostRepository์™€ PDO๊ฐ€ ํ•จ๊ป˜ ์ž‘๋™)
        $newPostId = $this->postRepository->create($title, $content);
        $retrievedPost = $this->postRepository->find($newPostId);

        // Assert
        $this->assertNotNull($retrievedPost);
        $this->assertEquals($title, $retrievedPost['title']);
        $this->assertEquals($content, $retrievedPost['content']);
        $this->assertEquals($newPostId, $retrievedPost['id']);
    }

    public function testNonExistentPostRetrieval(): void
    {
        // Act
        $retrievedPost = $this->postRepository->find(999); // ์กด์žฌํ•˜์ง€ ์•Š๋Š” ID

        // Assert
        $this->assertNull($retrievedPost);
    }
}

์œ„ ์˜ˆ์‹œ๋Š” PostRepository์™€ ์‹ค์ œ #PDO #๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค #์—ฐ๊ฒฐ์ด ํ•จ๊ป˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์˜ˆ์š”. TestDatabase ํ—ฌํผ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ #ํ…Œ์ŠคํŠธ #์ „์šฉ #DB๋ฅผ ์„ค์ •ํ•˜๊ณ  ๋งค ํ…Œ์ŠคํŠธ๋งˆ๋‹ค ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”.



์š”์•ฝ


#ํ†ตํ•ฉ #ํ…Œ์ŠคํŠธ๋Š” ๊ฐœ๋ณ„ ๋‹จ์œ„๊ฐ€ ๊ฒฐํ•ฉ๋˜์–ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์—ฌ, ์‹ค์ œ #์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋™์ž‘๊ณผ ๊ฐ€์žฅ ์œ ์‚ฌํ•œ ํ™˜๊ฒฝ์—์„œ ๋ฌธ์ œ๋ฅผ ์ฐพ์•„๋‚ด๋Š” ๋ฐ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ด์š”. #PHPUnit๊ณผ ์ ์ ˆํ•œ #ํ™˜๊ฒฝ #์„ค์ •, ๊ทธ๋ฆฌ๊ณ  #Fixtures ๊ด€๋ฆฌ๋ฅผ ํ†ตํ•ด ํšจ๊ณผ์ ์ธ #ํ†ตํ•ฉ #ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•จ์œผ๋กœ์จ #PHP #์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์‹ ๋ขฐ๋„๋ฅผ ํฌ๊ฒŒ ๋†’์ผ ์ˆ˜ ์žˆ์–ด์š”.




๋น ๋ฅธ์†๋„, ๊ฐ„ํŽธํ•œ์‚ฌ์šฉ, ์žฅ์• ์—†๋Š”VPN, ์‚ฌ์šฉ์ด๋ ฅ์—†๋Š” ๊นจ๋—ํ•œ ์•„์ดํ”ผ

https://vpn.luzensoft.com