0

Let's say my object needs to use an API to communicate with a device. The API call that I need is Api.do_something().

What would be the best way to solve this assuming that I need to call it only once? I'm inclined to use the third option but isn't dependency injection really too much of a hassle when I only need to call it once? The simplest solution is the first one, but then I have to mock Api().do_something() every time my test uses do_stuff(). On the other hand with the dependency injection I have to supply a stub object anyway.

1)

class MyObject(object):
    def do_stuff():
        return Api().do_something()

2)

class MyObject(object):
    def __init__():
        self.api = Api()

    def do_stuff():
        return self.api.do_something()

3)

class MyObject(object):
    def __init__(api):
        self.api = api

    def do_stuff():
        return self.api.do_something()
4
  • 2
    "I'm inclined to use the third option but isn't dependency injection really too much of a hassle when I only need to call it once?" Why would you believe so? Commented Jun 21, 2017 at 16:40
  • I'm basically introducing a design pattern that complicates the code, makes creation of the object harder and in return I get... slightly better unit tests? I also have to instantiate the api everytime I create MyObject, and now when it's actually needed for the call. Commented Jun 21, 2017 at 16:41
  • 4
    Sounds like you already know the answer. Commented Jun 21, 2017 at 17:04
  • Yes, but I'm really unsure about it, hence my question. Being cryptic doesn't help ;) Commented Jun 22, 2017 at 9:06

1 Answer 1

0

Every piece of code (function, class, method) has two clients:

  • the other code using this code is the primary client

  • the unit tests are a secondary client

When designing your code, you should take both clients into account. Making design choices that completely defeat the purpose for the primary clients is pointless, but making compromises to make testing easier is often worth it. When tests are easier you are more likely to write good tests, which indirectly makes your code more robust and easier to change in the future.

Dependency injection is one such thing that complicates your code, but really pays off for testing. Any time your code uses a global variable, your tests become more fragile because they have to test this implicit dependency. Explicit dependency management through constructor injection is vastly preferable.

In your specific example, options 1 and 2 are basically equivalent: the MyObject instantiates the Api dependency itself. In option 3, you use constructor injection for this dependency. So if you are testing the MyObject, it would be preferable to chose option 3.

If however this really just is a simple class that translates method calls to this specific API, then there is no point in making the API configurable: MyObject is already inherently coupled to the API, MyObject represents that API. In this case, the dependency from clients onto MyObject should be subject to dependency injection instead.

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.