Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrites the Mocking section: introduces Mox #2338

Closed
wants to merge 2 commits into from
Closed

Rewrites the Mocking section: introduces Mox #2338

wants to merge 2 commits into from

Conversation

fireproofsocks
Copy link

There seems to be a fair amount of confusion surrounding mocks in Elixir. You CAN use mocks in Elixir, and although there are some considerations for asynchronous execution, the mechanics and preparation are not vastly different than other languages, so I wanted to set the record straight and provide a walk-through that explains a bit of the philosophy so we can understand and use the Mox library.

There seems to be a fair amount of confusion surrounding mocks in Elixir. You CAN use mocks in Elixir, and although there are some considerations for asynchronous execution, the mechanics and preparation are not vastly different than other languages, so I wanted to set the record straight and provide a walk-through that explains a bit of the philosophy so we can understand and use the Mox library.
@fireproofsocks fireproofsocks requested a review from a team as a code owner June 20, 2020 02:23
@doomspork
Copy link
Member

doomspork commented Jun 21, 2020

Thanks for the contribution @fireproofsocks! This is a tricky change. Mox is not an official Elixir core library so traditionally we do not reference those in the lessons themselves. We could link to a lesson on Mox, but I don’t think the basic lesson is the place to introduce this library. We also do not link out to anywhere other than official docs, so the link to Plataformatec needs to go.

In my 5 or so years of Elixir I still haven’t needed a mock and I’m not sure we want to suggest that approach so early in the lessons when in fact, it would likely only confuse people’s understanding of testing in FP.

I think we need to discuss this with the larger @elixirschool/developers group before considering a merge.

@fireproofsocks
Copy link
Author

fireproofsocks commented Jun 21, 2020

The link to Platformatec was already in the docs -- that's not something I added. So if it "needs to go", you should remove it from the existing docs. Secondly, that article is literally one of the only articles about this topic and it is authored by José himself, so I would think that would make its inclusion viable. The same justification I think applies to Mox itself (also authored by José). Because Mox handles all the subtler issues (primarily those of asynchronous execution) and covering that in a "package-neutral" way would require an entire chapter of explanation on macros and code reflection, IMO it makes sense to put weight behind the elegant solution that Elixir's author devised.

The testing of certain execution paths is only possible with mocks (or with some variant of the "dependency-injection" method outlined), so it's a valid topic for any serious discussion on testing.

The thing that prompted me to open this PR was what I felt was misinformation re mocks being "highly discouraged": that is not the case. After many discussions in and out of the forums, my take on this is that the misunderstanding has arisen from the strange Ruby-esque (?) distinction about mocks as a verb vs. mocks as a noun and the general disinclination to achieve 100% test coverage (or close to it). In other words, some of the smelly bizzarro monkey-patching "mocks" favored by Ruby/Python/et al may be highly discouraged (and perhaps with good reason), using mocks to fully test your code, however, is absolutely a valuable tool.

If you still don't feel that this is an appropriate PR, I would be happy to rewrite my notes as a blog post on Medium or somewhere, but I would rather not re-invent the wheel when THIS site is a much better reference for the topic. At a minimum, please consider rephrasing the section on mocks so it doesn't turn people off to them -- I could put in a separate PR that more or less truncates the entire section (or perhaps, moves it to a separate section altogether).

PS Did we meet at an Elixir meet in Denver?

@SophieDeBenedetto
Copy link
Contributor

Thanks for raising this discussion @fireproofsocks! The topic of mocking in Elixir is definitely an interesting one and a lot of misunderstanding surrounds it, in my opinion due to the "noun vs. verb" distinction.

I think that the current lesson's statement:

The simple answer to mocking in Elixir is: don’t

is meant to refer to mocking as a verb. Instead, the best practice is:

...to explicitly define interfaces (behaviors) for code outside your application and using Mock (as a noun) implementations in your client code for testing.

And I think this approach is what your PR outlines in the lead-up to the Mox content.

I think this lesson could in fact use some updating along the lines of the first part (pre-Mox) of your proposed changes. In my opinion, the content you included more or less outlines and gives specific examples of what we currently suggest in the lesson:

To switch the implementations in your application code, the preferred way is to pass the module as arguments and use a default value. If that does not work, use the built-in configuration mechanism. For creating these mock implementations, you don’t need a special mocking library, only behaviours and callbacks.

Although I think if we are going to expand on this topic with examples and more detailed explanation, we should include the whys and hows of using behaviours in any mock implementations.

On the topic of Mox however--Elixir School currently aims to provide lessons on Elixir core library offerings only. It's my understanding that we want to avoid putting out opinions on non-core library offerings at this time. While Mox is the go-to mock library for Elixir in my personal opinion and professional experience, it is also the case that there is "more than one way to peel the orange" of mocks in Elixir tests, as this recent Twitter convo once again illustrates.

How would you feel about:

  1. Updating the current lesson to clarify the difference between "mocking" (verb) and "mocks" (noun), with some examples of how to leverage mocks-as-a-noun using Elixir core libraries
  2. Publishing a blog post on Mox by reworking the Mox content from this PR? @fireproofsocks not sure if you've had a change to check out our blog yet but I think a post on using Mox would make a great addition!

@doomspork
Copy link
Member

The link to Platformatec was already in the docs -- that's not something I added.

Ah, that should not have been in there so I can review and remove it, sometimes these things slip by. We have tried really hard to avoid linking to anything but official Elixir documentation so as not to show a preference for one company / consultancy / library. I've always felt that while this may make a few things harder, it allows us to avoid a lot of unpleasantries.

Secondly, that article is literally one of the only articles about this topic and it is authored by José himself, so I would think that would make its inclusion viable. The same justification I think applies to Mox itself (also authored by José).

I fully understand but José runs a for-profit Elixir consultancy. Many other people who've contributed to Elixir School do as well but they have had to forego free links to their business. I've avoided linking to employer blogs even though they've allowed me to dedicate a % of my paid time to Elixir open source.

José is always welcome to author blog posts here too 😀 Maybe this is a good opportunity for someone with less name recognition to get an opportunity to share some of their lessons.

The testing of certain execution paths is only possible with mocks (or with some variant of the "dependency-injection" method outlined), so it's a valid topic for any serious discussion on testing.

Mocking and DI are two different things to me and I think it's worth keeping them separate. That may require expanding on this article to better articulate these approaches.

The thing that prompted me to open this PR was what I felt was misinformation re mocks being "highly discouraged": that is not the case. After many discussions in and out of the forums, my take on this is that the misunderstanding has arisen from the strange Ruby-esque (?) distinction about mocks as a verb vs. mocks as a noun and the general disinclination to achieve 100% test coverage (or close to it). In other words, some of the smelly bizzarro monkey-patching "mocks" favored by Ruby/Python/et al may be highly discouraged (and with good reason), using mocks to fully test your code is absolutely a valuable tool.

It may not always be the case today but the vast majority of people coming to Elixir have come from a Ruby background which is why this section reads like it does. I still personally don't think mocking is as critical as people in the Elixir space make it out to be, defining know stubs is easy and easy to reason about.

That all said, I'm all for including more content but I don't believe this Basic Testing lesson is the place for Mox.

Publishing a blog post on Mox by reworking the Mox content from this PR? @fireproofsocks not sure if you've had a change to check out our blog yet but I think a post on using Mox would make a great addition!

@SophieDeBenedetto / @fireproofsocks I think a blog post would be great but even better why don't we add a Mox lesson under Specifics or Libraries (aside: we should figure out a way to merge these sections maybe?)? My thinking behind this is:

  1. @fireproofsocks does raise a good point that there is some confusion around this area in the community, clarifying in our Testing lesson would be a good start, covering Mox would also be a good addition*
  2. As a separate lesson we can reference the Mox lesson from within the Testing lesson
  3. Lessons are translated whereas blog posts are not. I think getting the Mox content would be huge.

PS Did we meet at an Elixir meet in Denver?

You may have met Sophie or Michael, I unfortunately sustained a serious back injury a few weeks prior and was stuck in CA waiting for clearance to fly again so I missed out. I am however based in Denver, should you ever be in these neck of the woods reach out and we'll grab some coffee 🎉

@SophieDeBenedetto / @fireproofsocks likely a conversation that involves others from the org but what about considering an additional Testing section in the Advanced category? Allowing this lesson to touch on how to do the basic testing and principles with another lesson that covers more advanced techniques like DI, mocking with Mox, and property testing with the latter two also linking our to their dedicated articles. You'd also be introduced to these topics after you've learned more about modules and asynchronous work.

Thoughts?

@doomspork
Copy link
Member

I want to make sure to address this too: @fireproofsocks please don't think we're pushing back because we don't want your contributions 😰

We love when passionate people such as yourself are willing to share what you know with the greater community. It's not everyday we get to engage in conversations about the content with other passionate folks new to the org. You bring a fresh set eyes to things. 😁

These additions are great I just want to make sure we find the place for them in the content. We really hope you'll continue to share your ideas with us, we're always looking for new contributors for Elixir School and the larger https://github.com/beam-community org.

@fireproofsocks
Copy link
Author

fireproofsocks commented Jun 22, 2020

Re item 1: unfortunately I don't think I'd be able to shed any light on the distinction between mocking as a noun vs. as a verb because I found the article on the subject to be nearly unintelligible (!). That may sound harsh, but based on conversations with and posts by other developers, I think my confusion was representative. Perhaps my inability to comprehend this distinction stems from my background in languages which never relied on the tortured constructions that seem to be the status quo in Ruby and Python testing where dependency injection et al is rare (but that's just my guess). In any case, I don't think it's useful to harp on the distinction.

Rather it would be far more important IMO to demonstrate through example how to properly handle testing code where simulated responses need to be given.

Although the first part of the code I shared I found to be a valuable entry point into how to construct code to allow for better testing, the intermittent problems that arose from its use during asynchronous test execution and from ad-hoc functions not constrained by contracts were as subtle as they were difficult to identify and solve. In other words, omitting a library like Mox which solves these problems would require a much longer conversation on the minutiae surrounding test execution and contracts which, although interesting, may not be as beneficial as just demonstrating a valid pattern.

Re item 2: If your documentation has as its goal "purity" and not necessarily "practicality" (i.e. thou shalt not reference anything but the core library), then would it be acceptable to reference the blog post in the docs? Again, the primary problem requiring a solution here is the dearth of accurate/practical information about mocks/testing in Elixir -- the exact placement of any remedy is secondary to me, I just want to see improvements somewhere.

@fireproofsocks
Copy link
Author

@doomspork / @SophieDeBenedetto : if we want to tackle this as a blog post, I think it would make a lot of sense to pair up Mox with ExCoveralls as part of drilling down to get 100% code coverage.

Copy link
Contributor

@gemantzu gemantzu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would only suggest two things:
a) make it so a new phrase is in it's own line.
b) move this into it's own lesson, and reference it in testing.
The second part is because we don't want to cram more stuff into the existing lessons, it makes it harder for translators to follow a change.

@gemantzu
Copy link
Contributor

Re: conversation above, I believe we should avoid doing blog posts when there is stuff that can be updated and be put to good use later. Write a blog post when it's about an opinion, a TIL, a review, but everything else should be lessons.
A mox lesson would be perfectly fine, and to be honest, I don't care if it's an official library or not, the elixir community is content starved, so attempts like the one @fireproofsocks put here is very welcome to my eyes :)
Re: if a mock is useful or not, I have used it in a project in the past with some colleagues and at the time I could use a good tutorial like this one.
Thanks @fireproofsocks :)

@SophieDeBenedetto
Copy link
Contributor

@doomspork @fireproofsocks I love the idea of putting this lesson under Libraries and linking to it from this section of the testing lessons 🚀

@doomspork could you elaborate a bit more on what clarifications/updates you'd like to see in this lesson on the topic of mocks though?

@doomspork
Copy link
Member

@doomspork could you elaborate a bit more on what clarifications/updates you'd like to see in this lesson on the topic of mocks though?

@SophieDeBenedetto are you asking about my comment "what about considering an additional Testing section in the Advanced category"? If so I guess I am thinking we clean up the Basic Testing lesson to stay basic and expand on the more advanced topics (DI, mox, bypass, property testing) in an Advanced Lesson.

@gemantzu
Copy link
Contributor

RE: linking to other blog posts, I agree, we shouldn't do it. @fireproofsocks you should remove mentions of Jose and his blog post and the lesson should be solid :)

… before and after code blocks, corrects mention of 'expect' as a function (it is not a macro), combs through for better readability
@fireproofsocks
Copy link
Author

Ok, I made changes per the suggestions and gave the verbiage a comb-through. Please let me know if anything else needs attention.

@fireproofsocks
Copy link
Author

Bump? Is something else required? Thanks!

@SophieDeBenedetto
Copy link
Contributor

Hi @fireproofsocks! Sorry this seems to have slipped through the cracks, thank you for the ping 🔔
I think the back-and-forth on this issue got a little confusing but I agree with @doomspork that we can introduce a lesson on Mox but that it belongs under Specifies or Libraries, rather than in the basic testing lesson. How do you feel about @doomspork's earlier suggestion:

why don't we add a Mox lesson under Specifics or Libraries (aside: we should figure out a way to merge these sections maybe?)? My thinking behind this is:

  1. @fireproofsocks does raise a good point that there is some confusion around this area in the community, clarifying in our Testing lesson would be a good start, covering Mox would also be a good addition
  2. As a separate lesson we can reference the Mox lesson from within the Testing lesson
  3. Lessons are translated whereas blog posts are not. I think getting the Mox content would be huge.

I know you mentioned that you didn't feel super confident addressing the first point by updating the existing Testing lesson. I'd be happy to open a PR to that effect and you can take over basically just taking the new Mox content you added here and PR'ing it as a separate, standalone lesson either under the Specifics or Libraries directories and linking to it from our existing testing lesson.

Let me know what you think! 🌞 🍪 🧁

@fireproofsocks
Copy link
Author

That sounds fine -- as I mentioned, the overall organizational strategy of the documentation isn't something I care overly much about, my priority is sharing accurate information. If you can open a PR to that effect with these changes going into the proper place, that would be great.

I'm not sure whether I expressed any doubts as to updating the current lesson, but that was not my intent. My priority continues to be to nix the misleading/incorrect statement that Elixir discourages mocks -- I've encountered too many developers who pointed to this page as their sole justification as to why they didn't bother writing tests for things that required mocks.

Can we make a smaller PR against this page that corrects the problematic statement and links to the Specifics or Libraries PR? Thanks for clarifying!

@doomspork
Copy link
Member

@fireproofsocks I think that would be a great approach (smaller update, link to lesson). A lesson on Mox will allow us to expand on how to use it more in-depth.

Very exciting content 🎉

@fireproofsocks
Copy link
Author

Great. I propose that we do this:

  1. @SophieDeBenedetto creates the other PR in the appropriate place, it gets merged... then...
  2. We can close this PR
  3. Open a new smaller PR that adjusts the text and links to the the PR from step 1.

Sound good?

@SophieDeBenedetto
Copy link
Contributor

Great. I propose that we do this:

  1. @SophieDeBenedetto creates the other PR in the appropriate place, it gets merged... then...
  2. We can close this PR
  3. Open a new smaller PR that adjusts the text and links to the the PR from step 1.

Sound good?

Sounds good to me--I'd be happy to open a PR moving your Mox lesson to a new location. In that same PR I will update the existing test lesson to clarify the mocking recommendations and link to the new lesson.

Thanks again for you contributions @fireproofsocks 🔥 🧦 😄

@SophieDeBenedetto
Copy link
Contributor

Closing in favor of new PR here #2343

@doomspork doomspork closed this Jul 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants