4

As a developer I should strive for low coupling between classes.

But low coupling doesn't mean "No coupling" so sometimes I have to allow some code flexibility and use "new" inside a domain model. (I'm sure everybody does this in real production code)

If I use "new" inside a method to create an object and I have to unit test this method I got a problem. Because I can't mock the objects I can't test the method in isolation. I know I can use dependency injection or I can send objects as parameters but I'm not talking about this clear cases.

Is this acceptable in practice?
Is there a better way? (I can't always inject)
Is this a unit test or an integration test?

PHP example:

class Car {
   protected $objDoor;
   public function createComponents() {
       $this->objDoor = new Door();
   }
}
4
  • 1
    But you can mock the objects created with new. Just use a suitable mocking tool for your language of choice.
    – Rogério
    Jul 30, 2013 at 15:57
  • @Rogerio, can you provide a link to a tool of your choise that does this?
    – johnlemon
    Jul 30, 2013 at 16:18
  • For the Java language: PowerMock and JMockit (my own). For C#: TypeMock Isolator, JustMock (commercial tools), and MS Fakes (with VS 2012). For Groovy: Spock. For Ruby: Mocha. For Python: Mock. Unless I am mistaken, they all support mocking of new-ed objects.
    – Rogério
    Jul 30, 2013 at 17:44
  • "If I use "new" inside a method to create an object and I have to unit test this method I got a problem." I'm not sure if this is accurate. Say you create some "List" or "String"--usually there arent issues with that :). Also I think you will only have a problem if that object has an external dependency which you need to mock out, or if your test has to inspect that some method was called on that new object. Otherwise the test will be using production code, which is fine.
    – jordan
    May 9, 2014 at 17:56

2 Answers 2

4

Dependency Injection

I think is strongly depends on what object you are creating. If you create object that you then return, it is somewhat part of the specification of the method. In that case it would be basically possible to do a unit test.

As you would do a unit test for the class in question (the one you use new on) as well, this shouldn't be the main problem. But if you create an object and do some stuff with that object (produce side-effects), you should use injection. This is true even more if you get all the parameters for the constructor call as parameters of your method. Simply create the object before calling the method and give the reference instead.

But of course that would imply that the method in which the object is created, would be doing the same thing now.

That being said you will need some kind of central mechanism that handles the dependency injection. Symfony provides a Dependency Injection component that handles that stuff.

Code coverage

It is important to have code coverage. It depends strongly on your project how well that can be done. Whenever possible unit tests should be written. On top of that you should use functional tests that test a certain function (and thereby the interaction of needed classes). All in all that should fit your need.

0
  > Is there a better way? (I can't always inject)

Not better but easier and equivalent:

If you donot want to inject a factory-method/class to create a new domain-child item you can implement a local protected virtual factory method

public class MyClassUnderTest {
   virtual protected MyObjectType createMyObjectType() {return new MyObjectType();}
}

and use this factory method instead of calling new MyObjectType() directly.

In the test you either inherit from MyClassUnderTest and overwrite createMyObjectType() with some mocking code or ask the mocking-framework to return some special childobject if createMyObjectType() is called.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.