Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Love Stole the Day
Nov 4, 2012
Please give me free quality professional advice so I can be a baby about it and insult you
I made this argument to my team last year and they were like "yeah but... naaaaaahh". I failed to influence them.

Adbot
ADBOT LOVES YOU

Jen heir rick
Aug 4, 2004
when a woman says something's not funny, you better not laugh your ass off
I don't really know the difference between fakes and mocks without looking it up. People I know use them interchangeably. To be fair the people I know are pretty dumb. As am I.

brand engager
Mar 23, 2011

Plorkyeran posted:

Mocking should be a tool of last resort when you can't figure out any other way to test some code, and as such going out of your way to ensure that every class in your codebase can be mocked is just a bad idea.

How do you write unit tests without them? Or were you only meaning integration tests?

Love Stole the Day
Nov 4, 2012
Please give me free quality professional advice so I can be a baby about it and insult you

brand engager posted:

How do you write unit tests without them? Or were you only meaning integration tests?

Pretend your component has a Controller - Service - Delegate way of separating concerns. The Controller takes in the request DTO and returns the response DTO... and the Delegate actually talks to the remote downstream stuff you need.

  • Create a new class that implements your MyDelegate interface by swapping out its dependency injection. Call it MyTestDelegateImpl (as opposed to the real one, MyDelegateImpl).
  • In your unit test, call your Controller's doTheThing() API operation, passing in some fake request (either give it a JSON file that you deserialize into the request DTO or just create it on the fly in the test's setup "// Given" section)
  • ((As the Controller does its normal thing, it'll use MyTestDelegateImpl's fake responses from the downstream service you're calling instead of actually trying to talk to the real thing, which is what an integration test does))
  • Do your assertions on whatever the Controller's doTheThing() API operation gives you in its response DTO output.
  • Check the line coverage and observe that you just covered a bunch of lines throughout your entire component with just a single unit test, and that now instead of testing based on each class' individual methods you are now testing based on what your component's actual use cases are supposed to be in reality... without having to wait anywhere near as long!
  • Notice that you are now able to cover more lines with fewer tests (with much fewer lines), which means you now know which actual use cases you're breaking when something breaks.
  • Notice that you can now delete a bunch of code because if you can't reach it from the Controller by passing in whatever special request DTOs you need, then your component's customers don't need it anymore. ((What a great way to discover whether code is actually dead or not!))

brand engager
Mar 23, 2011

That test delegate sounds like a mock to me

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

brand engager posted:

That test delegate sounds like a mock to me

Depending on how it's set up, a suitably simple fake and a suitably complicated mock behave roughly the same.

I think the value is that if you have 5 different functions in your delegate that mostly do the same thing for the same of testing, like pushing a value onto a container to be retrieved or validated later, writing the fake could end up even easier than writing the mock, and would be significantly easier to understand for someone looking at the test.

I can't speak to the code coverage aspect of it, but that sounds pretty nice too.

Love Stole the Day
Nov 4, 2012
Please give me free quality professional advice so I can be a baby about it and insult you
Instead of mocking literally every dependency of literally every class, you're mocking only the stuff that talks to external things... and so you're actually running the end-to-end code of the component itself, in the same way that it's actually used in reality. So, you're covering more lines with fewer tests, you're writing your unit tests in the almost the same way you write your integration tests, and you don't have to worry about fixing your broken unit tests every time you want to make a code change.

And since you're spending less time writing and fixing tests, you're also getting stuff done faster.

Blinkz0rz
May 27, 2001

MY CONTEMPT FOR MY OWN EMPLOYEES IS ONLY MATCHED BY MY LOVE FOR TOM BRADY'S SWEATY MAGA BALLS

Love Stole the Day posted:

Instead of mocking literally every dependency of literally every class, you're mocking only the stuff that talks to external things... and so you're actually running the end-to-end code of the component itself, in the same way that it's actually used in reality. So, you're covering more lines with fewer tests, you're writing your unit tests in the almost the same way you write your integration tests, and you don't have to worry about fixing your broken unit tests every time you want to make a code change.

And since you're spending less time writing and fixing tests, you're also getting stuff done faster.

That’s how mocks work, though?

Blinkz0rz
May 27, 2001

MY CONTEMPT FOR MY OWN EMPLOYEES IS ONLY MATCHED BY MY LOVE FOR TOM BRADY'S SWEATY MAGA BALLS
Like, why would you write a test that requires mocking everything? Mocks are for the dependencies of the things you put under test as a way to control complex upstream behavior.

brand engager
Mar 23, 2011

Volmarias posted:

Depending on how it's set up, a suitably simple fake and a suitably complicated mock behave roughly the same.

I think the value is that if you have 5 different functions in your delegate that mostly do the same thing for the same of testing, like pushing a value onto a container to be retrieved or validated later, writing the fake could end up even easier than writing the mock, and would be significantly easier to understand for someone looking at the test.

I can't speak to the code coverage aspect of it, but that sounds pretty nice too.

Usually our mocks are like
Kotlin code:
private val someService: SomeService = mockk()
private val classUnderTest = ClassUnderTestImpl(someService)

@Test
fun `test do whatever etc`() {
    val expectedResult = /* some return value */
    every { someService.getThing } returns /* some predefined instance or another mock */
    val actualResult = classUnderTest.functionThatUsesService()
    assertEquals(expectedResult, actualResult)
}

@Test
fun `test some other function that doesn't return a value`() {
    justRun { someService.putSomeThing(any()) }
    val testParam = /* whatever it is */
    val expectedParam = /* another thing derived from testParam */
    classUnderTest.someOtherFunction(testParam)
    verify { someService.putSomeThing(expectedParam) }
}
The mocks for the class being tested live inside the test class and have no permanent name

MajorBonnet
May 28, 2009

How did I get here?
I just need to vent here so I stop engaging with the person.

Please don't condescend to me about how rebases affect public branches when you don't understand how merges, rebases, and Gitlab MRs work.

Thank you for coming to my TED talk.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

brand engager posted:

How do you write unit tests without them? Or were you only meaning integration tests?

By definition if a mock is involved, you're testing the interaction of two components. If that statement sounds wrong to you, then it's a terminology issue around mocks/stubs/fakes/etc. where you're calling some other kind of test thing a "mock". If you insist on drawing a hard line between unit tests and integration tests but put things specifically testing the interaction of two components under unit tests then I think your categorization is silly. "Tests using mocks aren't unit tests" is sort of a hot take, but really I just think that pretending there's just two distinct categories of tests with a clear line between them is ridiculous and there's a whole gradient of what sorts of dependencies a test has.

I see mocks as a tool of last resort because at best you're specifically not testing the thing you've identified as the thing that needs to be tested, and at worst you're testing nothing at all. The more layers in between the code under test and the thing being mocked the more likely it is that the mock makes sense. If you're mocking a direct dependency, then you're mostly just validating that your understanding of that dependency was the same while you were writing the test and the non-test code. This isn't totally worthless and will sometimes help you notice problems, but obviously doesn't help at all with the more important question of if you understood the dependency correctly. If you're mocking something five layers away and are verifying that values are plumbed through correctly, then that's real code being tested even with the mock being involved.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
And to loop back to the original claim that writing interfaces for every class to enable mocking is dumb: the places where you want to use a mock in a test because the real thing inherently has side effects are nearly always obvious customization points where the interface is semantically meaningful. Your class which sends emails should implement a relevant interface not to enable mocking, but because you don't want to tightly couple your entire application to email sending. The interface-for-every-class rule is specifically requiring interfaces in places where they don't seem necessary to the author, which hopefully means they aren't sensible things to mock in the first place. If they get it wrong, you can just add the interface then.

brand engager
Mar 23, 2011

I think all of our code more complicated than truncating a string has dependencies passed into it, and since we only want to test one class at a time in our unit tests that means nearly every test has mocks. Everything calls either another one of our classes or eventually an android component at some point to actually accomplish anything. We don't have any tests where there are multiple classes' real implementations being tested at once which is what I'd call an integration test.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
That sounds like a lot of work put into making your tests do a worse job of catching bugs.

CPColin
Sep 9, 2003

Big ol' smile.
Interfaces, classes, mocks, and tests? How about you interface with my rear end while I mock your testes!!

Sagacity
May 2, 2003
Hopefully my epitaph will be funnier than my custom title.
Writing tests against mocks effectively makes your code refactor proof in the sense that any change you make to the underlying classes will instantly break a bunch of tests that explicitly rely on specific methods being called in specific orders, so well done

StumblyWumbly
Sep 12, 2007

Batmanticore!
My two favorite things are farting in elevators and rebasing things into dev

Xarn
Jun 26, 2015
Probation
Can't post for 3 hours!

brand engager posted:

I think all of our code more complicated than truncating a string has dependencies passed into it, and since we only want to test one class at a time in our unit tests that means nearly every test has mocks. Everything calls either another one of our classes or eventually an android component at some point to actually accomplish anything. We don't have any tests where there are multiple classes' real implementations being tested at once which is what I'd call an integration test.

Yep, this is what people usually mean when they say talk about codebases overusing mocks.

Vulture Culture
Jul 14, 2003

I was never enjoying it. I only eat it for the nutrients.

Sagacity posted:

Writing tests against mocks effectively makes your code refactor proof in the sense that any change you make to the underlying classes will instantly break a bunch of tests that explicitly rely on specific methods being called in specific orders, so well done
You just described completely correct test behavior for a workflow that either runs steps, in order, correctly or not

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
The big difference between a fake and a mock is that fakes are written by someone who understands the component they're faking, while mock behaviour is configured by someone who just uses that component and may or may not actually understand it.

Vulture Culture
Jul 14, 2003

I was never enjoying it. I only eat it for the nutrients.

Jabor posted:

The big difference between a fake and a mock is that fakes are written by someone who understands the component they're faking, while mock behaviour is configured by someone who just uses that component and may or may not actually understand it.
I've been working with my therapist on active listening, so I'm going to paraphrase to make sure I have this straight. There is no actual big difference between a fake and a mock after it has been written. It has auras projected onto it by its author, who may or may not know what they're doing.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Vulture Culture posted:

I've been working with my therapist on active listening, so I'm going to paraphrase to make sure I have this straight. There is no actual big difference between a fake and a mock after it has been written. It has auras projected onto it by its author, who may or may not know what they're doing.

Kind of true, but generally you have one fake implementation used everywhere (and fixed everywhere when one person finds any significant unintentional difference with the real system), vs. every single test configuring their own mock behaviour.

Blinkz0rz
May 27, 2001

MY CONTEMPT FOR MY OWN EMPLOYEES IS ONLY MATCHED BY MY LOVE FOR TOM BRADY'S SWEATY MAGA BALLS

Jabor posted:

Kind of true, but generally you have one fake implementation used everywhere (and fixed everywhere when one person finds any significant unintentional difference with the real system), vs. every single test configuring their own mock behaviour.

Or you have a fake per package/module/whatever that all have slightly differing behavior but which one is the correct one?????

smackfu
Jun 7, 2004

Sagacity posted:

Writing tests against mocks effectively makes your code refactor proof in the sense that any change you make to the underlying classes will instantly break a bunch of tests that explicitly rely on specific methods being called in specific orders, so well done

Unit tests in general fight against refactoring, because you are testing things at a certain fixed level of abstraction.

Vulture Culture
Jul 14, 2003

I was never enjoying it. I only eat it for the nutrients.

smackfu posted:

Unit tests in general fight against refactoring, because you are testing things at a certain fixed level of abstraction.
There's a good argument to be made that if you're changing a level of abstraction, you aren't actually refactoring, you're redesigning, rearchitecting, rewriting, re-something.

Threading this needle very carefully: I would argue that mocks mostly paper over the cracks in badly-designed or over-broad interfaces, by making it easy for developers to only mock out the parts they actually have to care about in the context of their specific behaviors. It's best when devs don't have to do this, but when you're working with something you don't have control over and the alternative is something like Localstack, it's okay to do things a little ugly.

CPColin
Sep 9, 2003

Big ol' smile.
I don't care if my tests make it take longer to do refactoring, because then I have to invent one fewer excuse for stand-ups

Falcon2001
Oct 10, 2004

Eat your hamburgers, Apollo.
Pillbug
I've spent a ton of time trying to think about testing stuff, but I don't have a ton of experience and I haven't worked on products with a robust existing test suite. But here's my approach (in Python, fwiw)

- I don't mock any part of our codebase unless it's extensively tested elsewhere and has a very narrow interface (one example is a ThingValidator that takes in a series of arguments and returns a simple True/False based on whether all those validations pass; we have unique tests for it.
- We work with a bunch of clients for various services, and that's the only main thing I patch and mock: the client itself and the responses, which I'll use the actual response class as much as possible if it's not a super complex object (which unfortunately some of ours are, I'm trying to think of a way to build some of these for reuse and still keep them easy to modify.) Building full fakes for them would be a huge amount of effort and we don't have the time, so this will have to do.

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...
I frequently mock code, just to let it know what I think about it. Oh yeah, login flow, REALLY GOOD JOB you're doing there when the network request stalls, maybe you should just wait another minute the user definitely won't be spending uninstalling you.

Jerk

Bongo Bill
Jan 17, 2012

The difference between mocks, fakes, doubles, stubs, etc. is pretty academic and in my experience the terms are not used or distinguished consistently.

Cup Runneth Over
Aug 8, 2009

She said life's
Too short to worry
Life's too long to wait
It's too short
Not to love everybody
Life's too long to hate


I had managers once who referred to all testing as unit testing and demanded we unit test everything when they meant they wanted us to make sure it worked before we shipped it

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Bongo Bill posted:

The difference between mocks, fakes, doubles, stubs, etc. is pretty academic and in my experience the terms are not used or distinguished consistently.

I don't really understand this point. Like yeah, you can split hairs about whether something is a fake, double, or stub and it doesn't really matter - but a mock is something created by a mocking framework while the others are not, which seems like a pretty bright and well-distinguished line to me.

HamAdams
Jun 29, 2018

yospos
at my last job we had a “unit testing” mysql database that we used in a similar way you’d use an in-memory db, except it was shared. so not only is it not actually unit testing, but you could cause all sorts of fun failures in other peoples tests

Lyesh
Apr 9, 2003

HamAdams posted:

at my last job we had a “unit testing” mysql database that we used in a similar way you’d use an in-memory db, except it was shared. so not only is it not actually unit testing, but you could cause all sorts of fun failures in other peoples tests

I like when that kind of setup in a five year old application someone wants me to rehabilitat, and it turns out the dev server with that db is long gone

AmbientParadox
Mar 2, 2005
whats the difference between a v&v engineer and a test engineer?

DELETE CASCADE
Oct 25, 2017

i haven't washed my penis since i jerked it to a phtotograph of george w. bush in 2003
sdet that's the way u like 2 b

Jen heir rick
Aug 4, 2004
when a woman says something's not funny, you better not laugh your ass off

Jabor posted:

I don't really understand this point. Like yeah, you can split hairs about whether something is a fake, double, or stub and it doesn't really matter - but a mock is something created by a mocking framework while the others are not, which seems like a pretty bright and well-distinguished line to me.

The difference is not really that important. If I tell someone, "Oh you'll need to mock out that dependency", and they proceed to make a fake. I'm not gonna care, and the difference is immaterial.

smackfu
Jun 7, 2004

This is development. It’s perfectly reasonable there are precise terms for things AND that people don’t use them precisely.

ultrafilter
Aug 23, 2007

It's okay if you have any questions.


AmbientParadox posted:

whats the difference between a v&v engineer and a test engineer?

Industry, mostly. Verification and validation are specific testing-related activities defined in ISO 9001, so if you see a job posting for a v&v engineer you can be pretty sure it's in an industry that cares about that particular standard.

Adbot
ADBOT LOVES YOU

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

smackfu posted:

This is development. It’s perfectly reasonable there are precise terms for things AND that people get really pedantic about everything.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply