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 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题