dongtiao0279 2018-07-06 09:43
浏览 40
已采纳

单元测试接受字符串参数以创建PDO对象的PHP类

I have a class (PDOMySQLForeignKeysToURLsService) that does exactly what it says on the tin, it takes a JSON encoded database entity, compares it to a configuration file and transforms any foreign key fields into URLs linking to other RESTful resources. i.e.

[
  {
    "ID": "1",
    "person_id": "1",
    "pc_name": "my_computer"
  }
]

assuming person_id is a foreign key in the database, will become something like

[
  {
    "ID": "1",
    "person_id": "http://localhost/api/db/person/1",
    "pc_name": "my_computer"
  }
]

because this service itself is initalized from a configuration file it can only accept text in it's constructor,

public function __construct(string $pdoDSN, string $username, string $password, string $tablename, string $schemaname)

everything seems to running fine and dandy, but now I want to write some unit tests for this class, and part of it requires that a PDO object is instantiated and the INFORMATION_SCHEMA table queried like below

  SELECT 
    *
  FROM
    INFORMATION_SCHEMA.KEY_COLUMN_USAGE
  WHERE
    TABLE_SCHEMA = ? AND
    CONSTRAINT_NAME != "PRIMARY" AND
    REFERENCED_TABLE_NAME IS NOT NULL AND
    REFERENCED_COLUMN_NAME IS NOT NULL

The method in which this occurs is in an implementation of an interface Resolvable, defining function resolveRequest(ServiceRequest $request, ServiceResponse $response)

I basically have no idea how to go around testing all of this besides setting up a schema/some tables in the tests set up? I have heard from my peers that this is bad practice and does not constitute unit testing but rather integration testing - so my question is how could I go about unit testing this method, is unit testing even appropriate here? The class is by definition very dependant on MySQL (and PDO). Should I write some kind of adapter around PDO and use a DI framework to inject it, and interface with that rather than PDO directly? I'm pretty lost at what to do, tbh, and don't understand the idea/how to mock dependencies that are only used within the scope of a method

  • 写回答

1条回答 默认 最新

  • dongxili9934 2018-07-11 03:14
    关注

    Even if you can't inject the PDO instance, there are still ways to unit test this - it just requires a little creativity. Probably the easiest way to unit test what you're describing would be to create a testable subclass that allows for injection. The exact details would depend on how your class is implemented, but a simple example might look something like this:

    class PDOMySQLForeignKeysToURLsService {
        protected $pdo;
    
        public function __construct(string $pdoDSN, string $username, string $password, string $tablename, string $schemaname) {
            $this->pdo = $this->createPdo(...);
        }
    
        // Encapsulate the PDO creation so that the subclass can override it.
        protected function createPdo(...) {
            return new PDO(...);
        }
    
        // Other methods omitted...
    }
    
    class TestablePDOMySQLForeignKeysToURLsService extends PDOMySQLForeignKeysToURLsService {
        // Override the constructor so you can pass in a mock PDO as the last parameter
        public function __construct(string $pdoDSN, string $username, string $password, string $tablename, string $schemaname, PDO $pdo) {
            // Save the injected mock PDO instance.
            $this->pdo = $pdo;
            parent::__construct(...);
        }
    
        // Override the creation so that you can just use the injected mock.
        protected function createPdo(...) {
            return $this->pdo;
        }
    }
    

    The TestablePDOMySQLForeignKeysToURLsService class would live next to your tests and you would use it in your test cases instead of the production class. The idea is that the "testable" class is a minimal extension of the production class - just enough to let you inject test doubles. This lets you test the logic from the production class and mock the database calls in your test without having to change the interface to the production class. It's kind of cheating, but it gets the job done.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?