<div dir="ltr">+1</div><div class="gmail_extra"><br><div class="gmail_quote">On 13 September 2014 08:18, Gustavo Niemeyer <span dir="ltr"><<a href="mailto:gustavo@niemeyer.net" target="_blank">gustavo@niemeyer.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Fri, Sep 12, 2014 at 3:16 PM, Nate Finch <<a href="mailto:nate.finch@canonical.com">nate.finch@canonical.com</a>> wrote:<br>
> In the thread Eric pointed to, Brad Fitzpatrick (one of the core Go<br>
> developers) says they prefer to keep tests in the same package unless forced<br>
> to have them in a different package to avoid circular dependencies.  I like<br>
> that.<br>
<br>
</span>Brad is a great guy, but defending a position because someone says so<br>
is not good reasoning, no matter who that is. I've provided a<br>
different point of view on that same thread, with reasoning, and had<br>
no counterarguments.<br>
<span class=""><br>
> I have always thought that export_test was an anti-pattern that should only<br>
> be used as a last resort.  The main problem I have with export_test is that<br>
> it makes your tests lie.  Your tests call foo.Create, but package foo<br>
> doesn't actually export Create, it has a non-exported create method, that<br>
> happens to get exported in the export_test file.  This makes your tests more<br>
> confusing than if you just called "create" from an internal test.  That's<br>
> even aside from the point of the busywork it creates from having to write<br>
> the file in the first place.<br>
<br>
</span>On the counter side, it greatly encourages you to keep your tests<br>
isolated from internal details, and forces you to make it very<br>
explicit when you're using non-public interfaces in your test, via a<br>
well known convention. Both are great real benefits, that easily<br>
outweigh the theoretical "lie" described.<br>
<br>
I'm not saying you should never use internal tests, though, but rather<br>
agreeing with people that posted before you on this thread.<br>
<span class=""><br>
> One argument for export_test is that it gives you a canonical place to go<br>
> look for all the internal stuff that is getting used in tests... but I don't<br>
> actually think that's very valuable.  I'm not actually sure why it would be<br>
> important to see what internal functions are getting exported for use during<br>
> tests.<br>
<br>
</span>The second part of that same paragraph answers the question with a<br>
counter example:<br>
<span class=""><br>
>  And in theory, if you're writing extensive unit tests, almost all<br>
> the internal methods would get exported there... so it becomes just a huge<br>
> boilerplate file for no good reason.  If you really want to see what<br>
> functions are getting exercised during tests, use code coverage, it's built<br>
> into the go tool.<br>
<br>
</span>This clearly describes one of the important reasons for the pattern.<br>
If every internal function is imported in tests, and assuming good<br>
code-writing practices for when to use a new function, it means the<br>
test is extremely tightly bound to the implementation.<br>
<span class=""><br>
> I agree with Gustavo's point that tests can be good examples of how to use a<br>
> package.  And, in fact, Go supports example functions that are run like<br>
> tests, but also get displayed in generated docs.  These example tests can<br>
> exist in the package_test package to make them very accurate representations<br>
> of how to use the package.<br>
<br>
</span>That was just one side I mentioned, in a long list of reasons, and in<br>
practice examples are pretty much always written well after the code<br>
is ready. How many public functions do you have in the juju code base?<br>
 How many of them are covered by those examples you mention?  How many<br>
of them are covered in tests?<br>
<span class=""><br>
> Most tests that are written to test the functionality of a package are not<br>
> actually good examples of how to use the package.  Most tests are just<br>
> isolating one part of the logic and testing that.  No one using the package<br>
> for its intended purpose would ever do that.  This is doubly true of unit<br>
> tests, where you may just be testing the input and output of a single<br>
> internal function.<br>
<br>
</span>That's very far from being true. My own tests exercise the logic I'm<br>
writing, with the API I designed and documented, and they reflect how<br>
people use that code. I commonly even copy & paste snippets out of my<br>
own tests into mailing lists as examples of API usage. Perhaps you<br>
write some sort of test that I'm not used to.<br>
<span class=""><br>
> I think our current trend of doing most tests in an external package has<br>
> significantly contributed to the poor quality of our tests.  Because we're<br>
> running from outside the package, we generally only have access to the<br>
> exported API of the package, so we try to "make it work" by mocking out<br>
> large portions of the code in order to be able to call the external<br>
> function, rather than writing real unit tests that just test one small<br>
> portion of the internal functionality of the package.<br>
<br>
</span>This insight fails to account for the fact that in practice "exported<br>
API" is precisely about the API that was made public in one particular<br>
isolated abstraction. Several of these "public APIs" are in fact very<br>
internal details to the implementation of juju, but that make sense in<br>
isolation. When you're testing these via their public API, it means<br>
you're actually exercising and focusing on the promises that were made<br>
to the outside implementation of juju itself, which are the most<br>
valuable guarantees to encode into test form. Developers should be<br>
free to refactor the implementation as necessary to improve clarity,<br>
performance, memory consumption, etc, as long as they keep those<br>
specific guarantees.<br>
<br>
Now, again, I'm not saying purely internal tests are not useful. I<br>
have those myself in a few cases. I'm just saying this is a damn good<br>
thing to have as a baseline.<br>
<br>
<br>
gustavo @ <a href="http://niemeyer.net" target="_blank">http://niemeyer.net</a><br>
<div class="HOEnZb"><div class="h5"><br>
--<br>
Juju-dev mailing list<br>
<a href="mailto:Juju-dev@lists.ubuntu.com">Juju-dev@lists.ubuntu.com</a><br>
Modify settings or unsubscribe at: <a href="https://lists.ubuntu.com/mailman/listinfo/juju-dev" target="_blank">https://lists.ubuntu.com/mailman/listinfo/juju-dev</a><br>
</div></div></blockquote></div><br></div>