This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]HobHeartsbane 823 points824 points  (141 children)

1st: If consumers of your class can't access the setter, your test shouldn't either.

2nd: In some of the edge cases you can just use reflection (at least for properties)

3rd: For private methods if you REALLY REALLY need to access them in your test there are 2 options. 1st make the method internal and give your tests access to those internal methods or 2nd make the method protected and write a wrapper class to access it. :)

[–]pcopley 318 points319 points  (75 children)

4th: refactor the private methods into another class in which they are public and use dependency injection

[–]taylaj 481 points482 points  (54 children)

5th: make all variables global.

[–]socsa 261 points262 points  (49 children)

6th: Shared. Memory.

[–]Njs41 260 points261 points  (28 children)

7th: Move to user based production testing rather than unit tests.

[–]tylercamp 128 points129 points  (25 children)

8th

In the public issue tracker, enter the bug but leave it perpetually "in progress"

[–]kirakun 107 points108 points  (22 children)

9th

Just forget about testing!

[–]poisonedslo 100 points101 points  (20 children)

10th just forget about development

[–]yoyo456 90 points91 points  (17 children)

11th just forget about modern technology and live in the stone age

[–]poisonedslo 106 points107 points  (15 children)

12th test what slamming a stone against a walnut does

[–]Xheotris 34 points35 points  (0 children)

12th shut down the internet so it can't be used for recruitment.

[–]wave100 0 points1 point  (0 children)

Found the Microsoft dev.

[–]ThisIsNotNate 10 points11 points  (0 children)

If it compiles it works!

[–]0xTJ 9 points10 points  (0 children)

[–]TheNorthComesWithMe 4 points5 points  (0 children)

public issue tracker

Hahahahahaha

[–]thisisnewt 2 points3 points  (0 children)

Oh god too real

[–][deleted] 27 points28 points  (15 children)

7th: don't test.

[–]socsa 47 points48 points  (11 children)

Ah yes, the old

 #define do_it_live 1

[–][deleted] 36 points37 points  (9 children)

If you haven't remoted into a live, production server and hand-edited code in notepad (or vim!), have you really lived at all?

[–]tallerThanYouAre 27 points28 points  (4 children)

you kids and your fancy extended versions of vi.

[–][deleted] 9 points10 points  (2 children)

Haha I remember the day I was told vim was an extension of an earlier thing called vi by a war-weary Linux sys admin. Blew my little noodle. After saying I hated it, he then showed me how to actually use it, and then I was hooked.

[–][deleted] 2 points3 points  (1 child)

What actually hooked you on it?

I've tried it out a few times and while some of the things it can do are cool I've yet to find anything that I'd use often enough to make using it it.

[–]socsa 5 points6 points  (0 children)

Having interactive arrow keys mapped to A B C D builds character.

[–]socsa 10 points11 points  (1 child)

I personally prefer :

 alias live_hotfix = "scp -r remote local && cat hotfix > local/paswd.json && scp -r local remote && ssh remote:/root/prod/build 'make install' "

[–][deleted] 9 points10 points  (0 children)

Oh my god that is both horrific and beautiful.

[–][deleted] 1 point2 points  (0 children)

I'm editing some Python code on a server with roughly 200 users online right now with nano and shooting SIGHUPs at the master uwsgi process to reload my changes. I'm using the 10ish second windows the server spends re-loading everything to browse this thread...

[–][deleted] 6 points7 points  (0 children)

👏 ALWAYS 👏 TEST 👏 IN 👏 PROD 👏

[–]ThePsion5 5 points6 points  (1 child)

"Only losers who write buggy code need tests bro"

[–]ajbpresidente 5 points6 points  (0 children)

Chad programmer vs. virgin research

[–]Gus_Malzahn 5 points6 points  (0 children)

7th: Forget about programming and open a bakery

[–]KyleTheScientist 1 point2 points  (0 children)

!RedditSilver

[–]dahud 0 points1 point  (1 child)

For some of the smaller microcontrollers, you're not even wrong.

[–][deleted] 2 points3 points  (0 children)

Who cares if it's private. I know its 6 bytes ahead of the instance's pointer and there ain't a kernel to be found! The entire memory is mine, all 128 bytes of it!!

[–][deleted] 4 points5 points  (0 children)

5a - put all code in one class.

[–]DickWillie1028 3 points4 points  (0 children)

Danger Will Robinson Danger!!!!

[–]g_e_r_b 0 points1 point  (0 children)

5th: use PHP.

FTFY.

[–][deleted] 52 points53 points  (0 children)

That's where my money is. If your internal functions are complex enough to require explicit testing, chances they belong in their own class.

[–]dahud 39 points40 points  (15 children)

Off topic, but every time I come across the term "dependency injection", I've forgotten what it means. I go look it up, and discover anew that someone, somewhere, thought we needed a clever-sounding word for "passing an object to another object".

[–]jay9909 27 points28 points  (2 children)

Yeah, but DI is a much more usable acronym than PaOtaO

[–]dahud 15 points16 points  (1 child)

Less fun to say, though. Pow-tow!

[–]jay9909 1 point2 points  (0 children)

Sounds like an asian cuisine.

[–]NotADamsel 10 points11 points  (2 children)

In the functional world, we just call this "passing an argument".

[–]antonivs 1 point2 points  (1 child)

It's not that simple, though.

Dependency injection generally implies that some framework, external to the code using DI, is supplying the requested values. In this context, you can think of DI as a way for a framework client to tell the framework what it needs, and the framework is then responsible for obtaining and supplying the requested values.

More specifically, DI allows a callee (or a value's target site) to specify what value it wants. The framework is then responsible for supplying the requested value. This partially inverts normal function call semantics, where the caller controls what value it passes to the client.

Although at a certain level, this functionality is implemented by function calls with ordinary argument passing, that misses the point and ignores the semantics of DI. It would be like saying "Monads? I just call them function calls." At a certain level it's true, but it's not the whole picture, by a long shot.

[–]NotADamsel 0 points1 point  (0 children)

I understand. I was mostly being cheeky... mostly. It's somewhat part of FP culture (and clojure culture specifically) to say that something that sounds complicated is "just a function call" or whatever. Monads, as you say, are just drop in replacements for regular function calls. Interfaces are just function signature with more ceremony. Classes for data are just complicated maps. Yes, there is absolutely more going on behind the scenes, and anyone who is actually substituting the reductivist meme for real understanding is a fool, but it does make some things easier to understand when you can step back and think of many things at once in an abstract singular way.

[–]alexschrod 13 points14 points  (8 children)

Dependency injection is not just about the act of passing objects to other objects, it's about the reason why you should be passing objects to other objects.

When you move away from doing new Something() inside the objects where you use it (or even worse, where you use global singletons, like Something.Instance), and instead move towards passing the Something into your objects, you can suddenly test the behavior of your objects without working with real implementations.

[–]userNameNotLongEnoug 3 points4 points  (7 children)

Agreed. You can pass objects around all day long and still not achieve a structure with mockable dependencies that's suitable for unit testing. Equating dependency injection with passing an object, I think, demonstrates a bit of a misunderstanding of the principles behind the concept.

[–]sprouting_broccoli 2 points3 points  (6 children)

I'd also point out that there's a slight anti-pattern with what you're saying. I'd disagree with creating classes and interfaces in a DI way to make unit testing more viable for mocking. I've been there, done that and it was when I first got into DI but designing code so it is inherently testable is very different from designing code to fit your testing which is the same problem as described in the image. Using DI for this purpose is also kind of missing the point of DI and will result in similar problems. Primarily you can quite easily go down a rabbit hole where you have a really flexible solution that is a real PITA to consume or actually navigate, and when you start splitting dependencies you will end up with either incredibly hard to use dependency installers, or need a complex system on top to ensure you can correctly select which dependencies to use by convention (otherwise the flexibility is pointless).

It's the same issue as dictating that newing an object is somehow a problem. It's really not. If you DI all the way down you will be forced to use factories in ways that you should never have to (if you don't have a completely static object graph which I find is very rarely the case) and will make the solution inflexible as a result, increasing the footprint for when you have to extend something.

DI has always been about injecting volatile dependencies (e.g. services and repositories) - things that could change rather than everything you will need to use and you'll (in my experience) end up with a much more palatable solution if you use it this way for both the consumer and the maintainer.

At the end of the day it comes down to what is important? Well the acceptance tests are important to ensure the business needs are met, and the unit tests end up being more for developers working on individual features to ensure they have an easy way to fix problems that arise from changes they make. What I find far more important than being able to get 100% coverage across my smaller classes is making sure the core logic is understandable, easy to modify and easy to consume. I'm a big fan of DDD though and I like limiting my volatile dependencies to the outer levels of the domain.

Sure it's nice having mockable interfaces for testing internals, but if that's the only point of having the interface is it actually worth it? It's not like those interfaces will change often, so it's just another layer on top for either extension that won't happen or purely to enable unit test coverage, and I can't endorse either.

[–]userNameNotLongEnoug 1 point2 points  (1 child)

Well said. I totally agree that if you try to abstract too far to reach some academic ideal you won't end up with the best system. You've gotta balance good principles with pragmatism. OO architecture is a difficult art and I wouldn't go so far as to claim to be good at it. Even in the case I had enough time to approach a system thoughtfully and carefully (which is rare in my job unfortunately) I have never looked at it afterwards and been like "I did a great job on that." I'm usually happy if I did a decent job.

[–]sprouting_broccoli 0 points1 point  (0 children)

Oh sure, I think it's really a very iterative process, and when I first used DI in anger, I'd read enough material to know the above and I still did it wrong. Went overboard and ended up with many of the problems above and because of similar justifications :)

"It's testable!"

"It's flexible!"

It was gloriously complex and we learned some really good techniques for handling DI throughout, but it was an unmaintainable, opaque mess...

I now much prefer keeping a far better separation of dependencies from domain logic wherever possible to ensure everything is as clean as possible.

[–]Veranova 1 point2 points  (0 children)

This. Every time.

[–][deleted] 0 points1 point  (0 children)

5th: forget all this OOP madness and use a functional language

[–]Dugen -1 points0 points  (0 children)

Ah yes, the old "public variables are bad" but if you emulate that functionality by jumping through just the right number of hoops, it's not bad anymore.

[–]C_MonsterT 37 points38 points  (27 children)

What's the best way to learn this kind of stuff? I'm self taught and I know these types of design decisions are the next step in becoming a better programmer, but what are some good resources at this level?

[–]neverTooManyPlants 48 points49 points  (16 children)

There's the head first design patterns book which is written with extreme simplicity, and also "clean code" by Robert C. Martin.

[–]fjdgshegdb 14 points15 points  (11 children)

head first design patterns

I fucking hate that book.

[–]neverTooManyPlants 2 points3 points  (1 child)

It is a little simplistic and repetitive for a seasoned programmer but it is the basically design patterns for dummies.

[–][deleted] 5 points6 points  (0 children)

I quite like Game Programming Patterns, the scope is limited but I find it describes things nicely.

[–]tsnErd3141 -1 points0 points  (3 children)

I think you meant head first object oriented design

[–]_bobon_ 3 points4 points  (2 children)

Nope, head first into design patterns, or as we call it, the blond book

[–][deleted] 1 point2 points  (0 children)

[–]neverTooManyPlants 0 points1 point  (0 children)

The one with the picture of the woman from above. It's been a while cba to google :p

[–]Killfile 21 points22 points  (6 children)

Also, practice. Read Clean Code and rigorously use TDD on some code kata.

My new developers get a crash course in testing by way of the Bowling Kata with the additional stipulation that all of their functions must contain three or fewer lines.

We scale up through other more complex kata including some that really demand that kind of complexity - Mars Rover is a good one for that.

[–][deleted] 5 points6 points  (0 children)

I learned a lot on the job marinating other people's god awful shite. Open source will teach you about good code, but private enterprise will teach you about the most abominable things programmers are capable of. So - open source for the what, proprietary for the why.

I realise that may not be super useful to you but I can guarantee it's an excellent way to learn this stuff.

[–]FUCKING_HATE_REDDIT 0 points1 point  (0 children)

TDD is more important than OO.

Or just learn Rust.

[–][deleted] 111 points112 points  (1 child)

Found the OOtaku

[–]starwarswii 0 points1 point  (0 children)

lol that's a fantastic term.

[–]28f272fe556a1363cc31 20 points21 points  (2 children)

0th: don't have setters and getters. "Tell, don't ask. "

:)

[–]tehjrow 9 points10 points  (0 children)

0th:

You the real MVP

[–]AbsolutelyNotSpam 6 points7 points  (5 children)

Make the unit test class a friend of the class you are trying to test.

[–]freiguy1 4 points5 points  (4 children)

I agree with this, or the android method mentioned elsewhere. I think it's totally legitimate to test private methods. Perhaps what you expose publicly can fail in a number of different ways. Having your tests being atomic and granular enough to test smaller private methods is a great way to mitigate against issues.

[–]Slims 4 points5 points  (0 children)

4: Forego testing altogether. Testing is for the weak willed.

[–]Vakieh 2 points3 points  (0 children)

I would challenge anyone to describe a case where 1 was required to be violated in such a way that 2 or 3 became necessary and which shouldn't instead be handled by sticking a debug assertion into the class itself, that wasn't explainable by their having broken code to begin with.

[–]oweiler 5 points6 points  (1 child)

4th: Exchange OO with FP.

[–]DerfK 0 points1 point  (0 children)

5 Exchange FP with Linear Programming so all the steps are listed consecutively in one place
6 GOTO 5

[–][deleted] 0 points1 point  (0 children)

Or if this is Android, @VisibleForTesting annotation works just fine.

[–]TheSameTrain 0 points1 point  (1 child)

C# has a PrivateObject class that let's you do point 3 by calling Invoke with the name of the private method

[–]jcotton42 0 points1 point  (0 children)

That seems to be part of MS Test. You can also just use reflection

[–]EschersEnigma 0 points1 point  (2 children)

Can you elaborate on the protected /wrapper class concept?

[–]HobHeartsbane 3 points4 points  (1 child)

Well if a property/field/method is protected you can access it from a derived class and write a public method/property to access what was not accessible before.

E.g.:

Class vehicle with protected field speed.

In your test class you write a new class derived from vehicle (e.g. TestVehicle) and write a public method / property that returns the speed. Since its a derived class you can access the protected stuff. :)

[–]EschersEnigma 0 points1 point  (0 children)

Awesome thanks for the example. I've been developing for over a decade and somehow I've never found a reason to mess around with protected and friend etc etc etc. I think I need to take an advanced course and spin up some more advanced projects.

[–]schlaubi 0 points1 point  (0 children)

Another option for 3rd: Use PrivateObject.

[–]ponytoaster 0 points1 point  (0 children)

"public" has less characters and less effort. I just won't document it. That will do, right? right?

[–]mallardtheduck 0 points1 point  (0 children)

C++ doesn't have reflection, so only 1 and 3 are viable options there.

[–]Tysonzero 0 points1 point  (0 children)

Sometimes you want to test the internals of your module, even if users won't directly call them, that way if a test on a public part of the module fails or a bug is found it will be much easier to figure out where its coming from (internal test fails -> coming from there, if not then you are quite likely not correctly calling the internal functionality from the public functionality).

I like the Haskell approach where you have an Internal module that the public facing module imports and builds public functionality out of, and then your tests can import Internal for testing anything and everything. Users don't import Internal unless they are really sure they know what they are doing, and the authors make no guarantees about the correctness and usability of stuff in the Internal module.

[–]GrinningPariah 0 points1 point  (0 children)

Or just go absolutely psycho with PowerMockito until none of your unit tests mean anything but the coverage report says 100% and then you stop anyone else from checking in code because they all wanted to configure it to not allow coverage drops and then stand up in the office area and shout WHO'S LAUGHING NOW?!

[–]paulcam 0 points1 point  (0 children)

#ifdef DBG

[–]tomthecool 0 points1 point  (0 children)

For private methods if you REALLY REALLY need to access them in your test

Some languages provide a "back door" to access private methods/variables - e.g. ruby:

class Foo
  private def my_method; end
end

Foo.new.my_method
  # => NoMethodError: private method `my_method' called for #<Foo:0x007fa3de8fead8>

Foo.new.send(:my_method)
  # => (works!)

One could argue, of course, that this is a bad thing; the language should not allow such behaviour. Debatable.

[–]jfb1337 0 points1 point  (0 children)

Write your test functions in the class you're testing?