Skip to main content
32 events
when toggle format what by license comment
Nov 18, 2020 at 0:04 comment added Mr.Mindor @RodneyP.Barbati if you meant how you would change the configuration of the DI framework, you usually don't have to, in most cases the DI framework wouldn't be involved in tests at all, really 99% of your code shouldn't even be aware a DI framework is in use.
Nov 18, 2020 at 0:00 comment added Mr.Mindor @RodneyP.Barbati not exactly sure what you mean by change the injected instance. My comment from Jun 1 '18 at 19:06 shows how you would pass a mocked dependency directly to the constructor during a test. Step 1, create mocked instances, MockOrOverrideForDep1() would be a function that returns a mocked out dependency.(I normally wouldn't use a function to set up a one-off mock, but not a lot of room in comments.) Step 2 create instance of ClassUnderTests, Step 3 test ClassUnderTests's behavior.
Nov 10, 2020 at 19:22 comment added Rodney P. Barbati Delayed response to @Mr.Mindor - I would ask you to explain how you might change the injected instance for use when testing? My point is that no matter what you do, you will always have some code (or configuration) somewhere which specifies a different instance be used - i.e. when testing, you have to use a different configuration for your classes that specifies mock instances. This means you have multiple artifacts for various purposes - same as the code above.
Nov 10, 2020 at 19:16 comment added Rodney P. Barbati ahnbizcad - if there are five versions of ADependency, then you will have 5 other classes that require their own testing - none of which would have any association with the example I provided. This is because this example is a method of mocking the instance used for ADependency - in other words, instances of ADependency are not being tested in this example.
Nov 7, 2020 at 3:40 comment added ahnbizcad With your example, what happens if there are 5 versions of ADependency? You then need to pass in different arguments into ADependency when instantiating it. And that means ClassUnderTest needs to pass those values and have constructor params. And now a dependent object dictated the interface of a caller class's constructor. Instead of the parent having to know the dependency's parameters, just pass the right instance of the dependent object... and you're right at dependency injection. no. your example is not equivalent.
May 26, 2020 at 9:03 comment added Stephen J @Warbo like a music player? Background music is an appropriate use-case. So's network data retrieval. There's only "massive bugs" if you don't know where your callbacks are at.
May 8, 2020 at 15:24 comment added Warbo @RodneyP.Barbati Re: "Unit testing is ever only one class deep". There are multiple definitions for terms like "unit testing"; some people use "unit" to mean a "unit of code" (e.g. a class); others mean "unit of functionality" (e.g. "logging in"). My experience is that the former requires a lot of effort and complexity for little to no gain. I've written a blog post about it
May 8, 2020 at 15:21 comment added Warbo @StephenJ "singletons' "where" is time-based" Uh oh, sounds like you're using shared mutable global state, which is a massive source of bugs.
Oct 24, 2019 at 21:02 comment added Stephen J You're right about the global singletons, and after much reading, I've found that the "cons" to using singletons also apply to dependencies, because they're basically global. The reason I'm interjecting is this: Singletons appear to be more appropriate when their behavior is re-usable between different programs. I personally use them, because DI is just as opaque, if not more. If I need to hot-swap a "helper", DI forces me to pick where in the tree to swap it, singletons' "where" is time-based. Just a trade-off on what to know when debugging. Less code, same result = happy programmers.
Oct 31, 2018 at 1:47 comment added Logan Pickup @RodneyP.Barbati To answer your question though - yes, I have places in my code with annotations, because type information is not always sufficient (usually this only happens when injecting interfaces that I didn't write); I also have places where an unknown number of the same type can be injected (plugin-style architecture); and I also have places where depending on which app is being built, a different implementation is injected.
Oct 31, 2018 at 1:43 comment added Logan Pickup @RodneyP.Barbati Whether you inject a single class or multiple is irrelevant. The point is to remove the dependency on the implementation, so that if the implementation changes (not necessarily to a different implementation), the user doesn't need to change/be recompiled/etc. too. I also find, personally, that the constraints imposed by using DI help clarify what a particular interface should look like, which in my experience (maybe not yours) leads to cleaner designs.
Oct 30, 2018 at 19:12 comment added Rodney P. Barbati @Logan Pickup - can you please provide the details of when you actually used DI to inject more than a single class. If you are using DI to inject more than a single implementation, then your annotations have enough information to identify that single class, but in a roundabout fashion - you can't just say "class", you have to describe a class that looks like this.
Oct 30, 2018 at 19:08 comment added Rodney P. Barbati @Ewen Unit testing is ever only one class deep - that's why they call it unit testing.
Oct 30, 2018 at 19:06 history edited Rodney P. Barbati CC BY-SA 4.0
added 213 characters in body
Jun 1, 2018 at 19:16 comment added Mr.Mindor And yes you are right that in most languages (at least that I'm familiar with) you can't or at least really shouldn't call virtual functions from constructors, but that isn't a sufficient argument for two step initialization over DI. If you use dependency injection via constructor parameters, the problem goes away completely. You can even still use factories and never have partially initialized objects public static ClassToBuild ImAFactory() { var dep1 = new DependencyOne(); var dep2 = new DependencyTwo(); return new ClassToBuild(dep1,dep2); }
Jun 1, 2018 at 19:06 comment added Mr.Mindor (cont) Additional developer overhead because they also have to somehow track which subclass and which dependency subclasses belong to which test or tests. Further you claim it is easier to do this than to use DI... How is writing, maintaining, managing the extra subclasses easier than var dep1 = MockOrOverrideForDep1(); var dep2 = MockOrOverrideForDep2(); var testSubject = new ClassUnderTest(dep1, dep2); ... rest of test (cont)
Jun 1, 2018 at 18:52 comment added Mr.Mindor @RodneyP.Barbati I think everyone commenting here noticed that your example wasn't supposed to be an example of DI. The problem is that you bill it as equivalent to DI and it is not. It is, as Logan described, pretty much the exact opposite: A specialized custom version of the class for each combination of dependency behaviors you might need to override. That can amount to up to as many sub classes as you have tests. No it does not cause runtime overhead, but it does lead to unnecessary overhead for the developers in the form of having to manage and maintain the extra code.
Jun 1, 2018 at 13:19 comment added T. Sar While I agree that DI is not the magic bullet a lot of people say it is, I'll have to say that everything down from your third paragraph is... weird.
Jun 1, 2018 at 13:04 comment added Warbo @RodneyP.Barbati Factories (methods or classes) are orthogonal to two-step creation. Whether we create a Foo object with a constructor or factory, we should get back a working Foo object, not a half-finished one. Also public APIs shouldn't expose implementation details like initializeDependencies. If you still want to expose initialiseDependencies (e.g. to avoid calling it from a constructor), put it in an UninitialisedFoo class with no other methods, and have it return a Foo object (calling it multiple times should work too).
May 31, 2018 at 21:12 history edited Rodney P. Barbati CC BY-SA 4.0
I wanted to clarify based on the comments...
May 31, 2018 at 20:23 comment added Rodney P. Barbati I guess no one noticed this wasn't supposed to be an example of DI. If it was, there would be more code. I'm showing how unit testing is easier without DI. For those of you poo-pooing two stage construction - I'll assume you've never heard of a factory or factory pattern. For those of you thinking that this adds overhead - you either aren't unit testing or your unit tests are embedded in your production code - good for you! Also, you can't or shouldn't call overridden methods from a constructor. The rest of you should try it before commenting.
May 31, 2018 at 12:35 comment added Warbo Adding to @Mr.Mindor: there's a more general anti-pattern "sequential coupling" which doesn't just apply to initialisation. If methods of an object (or, more generally, calls of an API) must be run in a particular order, e.g. bar can only be called after foo, then that's a bad API. It's claiming to provide functionality (bar), but we can't actually use it (since foo might not have been called). If you want to stick with your initializeDependencies (anti?)pattern, you should at least make it private/protected and call it automatically from the constructor, so the API is sincere.
May 30, 2018 at 23:27 comment added Mr.Mindor (cont) With initialization through the constructor parameters, you completely eliminate the need for all the boiler plate code your one sub class per test would require. You can keep all the sub classes for the dependencies if you really must, but those are the sort of thing mocking frameworks are written for. Lastly the bit about DI frameworks does actually offer something to the OP question hidden behind the rant. They are a tool that can have a steep learning curve and can be abused just like any other, and can make things worse if used inappropriately.
May 30, 2018 at 23:14 comment added Mr.Mindor There is so much wrong with this. As others have said, your 'DI equivalent' example is not dependency injection at all, it is the antithesis, and demonstrates a complete lack of understanding of the concept and introduces other potential pitfalls as well: partially initialized objects are a code smell As Ewan suggests, Move the initialization to the constructor, and pass them via constructor parameters. Then you have DI...
May 30, 2018 at 17:36 comment added GodsBoss Imagine you have class A with no dependencies, then B having A as dependency, C having B and D having C. Now you want a D which uses A', a class derived from A. B instantiates A, so you have to create B' instead. Then C', then D'. Writing one class forces you to create three others. With dependency injection you could just have wired your objects differently.
May 30, 2018 at 11:05 comment added Ewan if you use interfaces and move initializeDependencies() into the constructor its the same but neater. The next step, adding construction parameters means you can do away will all your TestClasses.
May 30, 2018 at 11:04 comment added Ewan its neat when you have only one level of class inheritance and one level of dependencies. Surely it will turn into hell on earth as it expands?
May 30, 2018 at 6:21 comment added Logan Pickup You've described not the equivalent, but the opposite of dependency injection. In your model, every object needs to know the concrete implementation of all its dependencies, but using DI that becomes the responsibility of the "main" component - to glue appropriate implementations together. Bear in mind that DI goes hand-in-hand with the other DI - dependency inversion, where you do not want high-level components to have hard dependencies on low-level components.
May 30, 2018 at 5:55 comment added BЈовић The problem with singletons is that they are making unit testing really difficult. Besides the different between a singleton and a global variable is quite small. DI is still way to go. And contrary to your answer, difference between singleton and DI is huge.
May 30, 2018 at 3:49 history edited Rodney P. Barbati CC BY-SA 4.0
added 373 characters in body
May 30, 2018 at 3:44 review First posts
May 30, 2018 at 12:16
May 30, 2018 at 3:43 history answered Rodney P. Barbati CC BY-SA 4.0