
Testing Without Mocks: A Pattern Language - jdlshore
http://www.jamesshore.com/Blog/Testing-Without-Mocks.html
======
miensol
I like your article a lot. I do have a hard time to map the layers you've
described (Application, Logic, Infrastructure) to a mobile/frontend/ui
application.

For instance in Android we've Activities/Fragments (and less commonly Views)
as the entry points to the application code. From there we might have [View
Models]([https://developer.android.com/topic/libraries/architecture/v...](https://developer.android.com/topic/libraries/architecture/viewmodel))
and External API clients that are clearly _infrastructure_.

From what I've seen it is common to call the External API clients from
ViewModels directly. (This is so we can test more logic outside of Android
runtime, AFAIK.)

If I get the layers you've described we should instead let Activity/Fragment
ask the ViewModel for some data and then use it to call the External API,
correct?

~~~
jdlshore
Thanks, I'm glad you like it. I haven't done any Android work, so I'm not sure
how the A-Frame Architecture applies. From my quick glance at the ViewModel
documentation you linked, that looks like Application layer code: in the first
example in that document, the `loadUsers()` call would turn around and call
the actual a specific Infrastructure Wrapper responsible for communicating
with the service that provides the users.

------
JayBazuzi
> there's no need to create interfaces for dependencies

I think in this context you're using `interface` in the way that C# uses it: a
point of abstraction and indirection.

I think you aren't using it in the API sense: the external surface of a thing.

If that's correct, you may want to clarify your wording. Perhaps "abstract
interface".

~~~
jdlshore
I meant in the term of the language construct. I'll think about how to make it
more clear...

~~~
jdlshore
I ended up just taking that paragraph out. I don't think it added much.

------
wpannell
Interesting innovation. Coincides with 2nd Edition of Martin Fowler's
"Refactoring," for which he chose to code in javascript. Interested in
feedback from the mocking pioneers — Steve Freeman, Nat Pryce, Keiþ
Braiþvvaite — and, of course, the father of TDD — Kent Beck.

Is there sample code illustrating the pattern language?

~~~
jdlshore
Other than the sample code in the article, my "WeeWikiPaint" project
demonstrates most of the infrastructure patterns, particularly in its server
code:
[https://github.com/jamesshore/lets_code_javascript/tree/epis...](https://github.com/jamesshore/lets_code_javascript/tree/episode614/src/server)

------
JayBazuzi
> This can result in multiple tests failing when a bug is introduced.

One way I approach this is "a bug will only cause one test to fail _at that
level of abstraction_".

------
JayBazuzi
I don't see ports-and-adapters (aka Hexagonal Architecture) mentioned. Is that
because you don't like it / don't find it useful?

~~~
jdlshore
I don't feel like I fully understand it.

~~~
JayBazuzi
P-and-A makes Simulators possible, which are the one kind of test double I'm
happy with. But your pattern language seems complete without it, so maybe I
don't need it as much as I thought.

Simulators fit right where you have Nullable Infrastructure. Having a null
object and a real object, instead of a single object with both null and real
behaviors is how I'd normally organize things. I write my Focused Integration
tests so they can be run against both the real and the simulator, to ensure
that they both agree on the contract. And just like the Nullable
Infrastructure, I can use the simulator in tests.

However, the real with with Ports-and-Adapters isn't the simulators (even
though everyone notices that first). It's the way a good Port abstraction lets
you organize your code well, writing it in terms that make sense in your
domain, instead of in terms of the dependency.

This is worth exploring further.

~~~
jdlshore
One of the key ideas of the Nullable Infrastructure is that all the semantics
of the infrastructure class remain _exactly the same_ other than disabling
external communication. So any logic inside the infrastructure code still
runs. This is important because we don't have broad integration tests.

That's why the null code is inside the infrastructure, instead of using the
classic Null Object pattern. It's also a major difference between it and
classic test doubles. And perhaps your simulators?

