How to use Dependency Injection with Static Methods?

后端 未结 3 1768
旧巷少年郎
旧巷少年郎 2020-12-14 21:10

Imagine there is a Customer class with an instance Load() method.

When the Load() method is called, it retrieves order details

3条回答
  •  伪装坚强ぢ
    2020-12-14 21:26

    Function Pointer Injection

    TLDR:

    Inject a function pointer into the Customer class. The value of this function pointer can be Order.GetAll in production, and MockOrder.GetAll in tests.

    EXAMPLE:

    The dependency (problematic static function we depend on):

    class Order {
        static func GetAll() -> [Order] {
            var orders = ... // Load from production source
            return orders
        }
    }
    

    Our dependent class (depends on static function):

    class Customer {
        func Init(getAllOrdersFunction) { // Arg is a func pointer
            self.getAllOrdersFunction = getAllOrdersFunction
        }
    
        func Load() {
            var orders = self.getAllOrdersFunction()
            // Do stuff...
        }
    }
    

    Production client class (performs the dependency injection):

    class BusinessLogicManager {
        func DoBusinessLogic() {
            var customer = Customer(Order.GetAll) // Prod func injected here
            customer.Load()
            // Do stuff...
        }
    }
    

    Testing client class (how unit test can inject a fake dependency):

    class CustomerUnitTests {
        static func GetFakeOrders() {
            var orders = ... // Hardcoded test data
            return orders
        }
    
        func TestLoad() {
            var customer = Customer(CustomerUnitTests.GetFakeOrders) // Fake func injected here
            customer.Load()
            // Verify results given known behavior of GetFakeOrders
        }
    }
    

    DISCUSSION:

    How you actually inject the "function pointer" will depend on the syntax and features available in your language. Here I'm just talking about the general concept.

    This isn't exactly a pretty solution. It would probably be easier if you can change GetAll to be an instance method (perhaps by introducing an OrdersLoader object, or by using Paul Phillips' answer). But if you really want to keep it as a static function, then this solution will work.

提交回复
热议问题