Clean Architecture / Should my acceptance tests involve the REST API call ?

299 views
Skip to first unread message

Michael Azerhad

unread,
Jan 21, 2015, 11:25:20 PM1/21/15
to clean-code...@googlegroups.com
Hi,

I watched every video of Uncle Bob (cleancoders) dealing with the concept of Clean Architecture.

In my current app, my end-to-end / acceptance tests only involve the "Use cases" part, in other words the Interactors part. 

Basically my server architecture could be clearly simplified as: 

  Controller (REST port) => Interactors (my use case) => Domain => Repository

My acceptance tests cover this portion (no http call, or anything outside prior to the pure business logic): 

 Interactors (my use case) => Domain => Repository

I learned the concept of "humble controller", meaning controller being totally devoid of business logic, that's why I judged not useful to involve the REST calls in my acceptance tests.
If any "bug" is discovered on the REST part, it would be most of the time an error of "configuration" like routing etc..

Guys, do you test the REST part in your acceptance test, meaning involving effectively the http protocol, like any real client would do ?
Should I write full functional tests, additionally to the acceptance tests ?

Thanks a lot,

Michael
 

gaz_edge

unread,
Jan 22, 2015, 4:02:25 AM1/22/15
to clean-code...@googlegroups.com
Whilst you are correct that your Controller should not handle business logic, REST is not business logic: it is a delivery mechanism,

Therefore it should be your Controller that calls your application code, and constructs the necessary View Model that your View then turns into your resource for transmission over HTTP.

With that being said, if you don't test your controllers, how will you know that you are outputting the correct resources?

Acceptance tests are designed to validate that your application behaves as your users expect. If your users will be consuming your application over a RESTful API, then you better make sure that API is tested in full.

michael azerhad

unread,
Jan 22, 2015, 6:26:59 AM1/22/15
to clean-code...@googlegroups.com
So IYO, humble objects should be tested as well.
--
The only way to go fast is to go well.
---
You received this message because you are subscribed to a topic in the Google Groups "Clean Code Discussion" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clean-code-discussion/PEIKHcq7GFY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clean-code-discu...@googlegroups.com.
To post to this group, send email to clean-code...@googlegroups.com.
Visit this group at http://groups.google.com/group/clean-code-discussion.

Michael Azerhad

unread,
Jan 22, 2015, 7:25:44 AM1/22/15
to clean-code...@googlegroups.com
In an Hexagonal architecture, controllers would be adapters.
There could be as many ports/adapters as we want:  REST, SOAP etc.

If you involve adapters (controllers) in your acceptance tests, you would completely be coupled to them, increasing time to complete a test, and dependent of the configuration files. 
IMHO, the goal of Clean/Hexagonal Architecture is to increase testability by deferring the input and the storage (repositoryImpl talking to database for instance). 

If your acceptance test focus on one adapter, it should focus on every one...would be a mess and a lot of duplicate test would be emerged.

IMHO, and as Vaughn Vernon explains in his red book IDDD:  

" A big advantage with Hexagonal Architecture is that Adapters are easily developed for test purposes. 
  The entire application and domain model can be designed and tested before clients and storage mechanisms exist. 
  Tests could be created to exercise Interactors well before any decision is made to support HTTP/REST/SOAP, or messaging ports. 
  Any number of test clients can be developed before the user interface wireframes have been completed. 

So, I interpret that Acceptance testing should focus on Interactors (use cases directly). 
However, in order to test a REST API, some system tests can be created covering the whole chain from the REST call to a real storage.
But those system tests would not test business logics so there would be one by distinct use cases.

There would be some system tests regarding each type of adapter.

gaz_edge

unread,
Jan 22, 2015, 9:20:28 AM1/22/15
to clean-code...@googlegroups.com
I think you are putting way too much attention on the word 'Acceptance', they are after all just a set of tests.  The term 'acceptance' is a very broad term used to validate that users of your system get what they expect. 

Presumably you already have tests for your interactors? They are your applications acceptance tests. They confirm that 'users' of your interactors (your controllers) get what they expect when they call the interactors.

Since you have already identified your delivery mechanism, it seems rather short sighted not to have a set of tests for them. If the wording really bugs you, call them RESTtul Acceptance tests to help you organise things in your mind.

Sebastian Gozin

unread,
Jan 24, 2015, 10:10:00 AM1/24/15
to clean-code...@googlegroups.com
I would also argue it is more important to have acceptance tests for your business logic and not necessarily for your transport adapters.
Which also goes against some of the advice others have given here... I guess we do not agree.

I don't mind having an acceptance for the existence of a specific transport channel but I would never test it in combination with any actual business rule.
I will simple assert it behaves appropriately for the various ways my business objects are allowed to interact with it and test the business components with their own acceptance tests.

I do not however have dedicated transport components for every possible business component. For example no BookController for a BookService.
I have a controller which derives context from the REST route or the message context and then selects the appropriate xService based on that.

Actually, from the latest clean coders videos about writing a compiler I've begun to wonder I could perhaps generate transport components based on a business component and some configuration.
A bit like what Apache Camel does through simple configuration. So why would I bother with acceptance testing a usecase through a system that will always do the same thing irrespective of the usecase it is serving?

gaz_edge

unread,
Jan 24, 2015, 10:42:43 AM1/24/15
to clean-code...@googlegroups.com
I think it all really comes down to your perspective and preferences. You can still achieve a decoupled application even if your acceptance tests start with the delivery mechanism in mind. When I know I am writing a RESTful api, my acceptance tests  have the api users in mind.

I use BDD style to write up my REST api acceptance tests, and then use those tests to drive the design of the application (interactors) for which I write unit tests.

For me, the benefit of having acceptance tests at the controller level is that they can perform quickly during initial development (using in memory databases, and test doubles) and then a quick switch around of my IoC container, and they then become my integration tests. Two test suites for the price of one!!

This gives me total confidence that when I push my code out to staging, it will be pretty certain to work. I run my integration tests one last time in staging to check all works well, and then its a push to production.

Without fully e2e testing the api in the way my users would use it (acceptance tests) I really wouldn't be able to sleep well at night.

If i then need to change delivery mechanism (say running the app locally through CLI) i then write BDD acceptance tests with CLI users in mind. The benefit obviously being that 95% of the application will already be coded, tested and ready to use (the interactors). All thats needed is to implement some CLI controllers, Views and maybe a local storage.

Now, for those thinking that you should be able to code you application without knowledge of the delivery mechanism and persistence, this is also possible. What i would do then would be to do BDD acceptance tests at the interactor level. 

Sebastian Gozin

unread,
Jan 24, 2015, 11:46:30 AM1/24/15
to clean-code...@googlegroups.com
It's not my experience you can realistically keep such a test suite performing well. REST means bootstrapping a server and even in-memory SQL databases tend to slow thinsg down significantly.
I know I am talking about a test suite running in minutes/hours vs seconds/minutes and that you may not care so much but I do and can imagine others would as well.

In any case I'm doing a cost/effort/scope/risk evaluation.

For example:
HTML (2%) > Javascript (15%) > REST (3%) > APP (70%) > SQL (10%)

I can live with 95% coverage provided I did integration tests the basic functionality of the transport layer.
Its a bit of a case where 8 + 2 equals 9 instead of 10 in terms of confidence but also 8 + 2 equals 16 in terms of effort.

Gareth Wedley

unread,
Jan 24, 2015, 3:34:51 PM1/24/15
to clean-code...@googlegroups.com
Who said anything about in memory SQL? Create interface gateways and you can use pure in memory object implementations. 

Depending on your web framework (if you use one), you don't even need to launch a server. Most offer a test setup with a mock server. You'd test real http requests in your staging environment which you only run when you are ready to deploy. 

My acceptance tests run as quick as my unit tests in my dev environment. 

Sent from my iPhone
--

Sebastian Gozin

unread,
Jan 24, 2015, 4:21:18 PM1/24/15
to clean-code...@googlegroups.com
Oh certainly.
I do that too.
To unsubscribe from this group and all its topics, send an email to clean-code-discussion+unsub...@googlegroups.com.

Ben Biddington

unread,
Jan 24, 2015, 7:01:04 PM1/24/15
to clean-code...@googlegroups.com

I am fond of being able to switch the driver implementation at runtime so I can have some long skewers (system tests) and some hexagonal ones.

Seems to help me keep the acceptance test language neutral also.

You received this message because you are subscribed to the Google Groups "Clean Code Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discu...@googlegroups.com.

Dave Schinkel

unread,
Aug 19, 2015, 11:01:50 PM8/19/15
to Clean Code Discussion
I'm curious to know how you're architecting your controllers, can you elaborate on the structure of them and inputs to your controllers?

Dave Schinkel

unread,
Aug 19, 2015, 11:02:57 PM8/19/15
to Clean Code Discussion
And what do your interactors look like as well...


On Saturday, January 24, 2015 at 9:42:43 AM UTC-6, gaz_edge wrote:

Dave Schinkel

unread,
Aug 19, 2015, 11:07:15 PM8/19/15
to Clean Code Discussion
The way I'm doing my REST API so far is I have the REST contracts (the interface) which in my case are Koa.js endpoints that are js route methods (get, put) that are defined via the koa.js router object

Then I have a koa.js route to controller mapper.  Incoming request comes in, and is mapped to a corresponding controller to process that http request.  In my controller I'm able to inject a gateway for instance that allows the controller to get stuff from the BL or whatever it needs.  I can then also mock the gateway for my unit tests as well.

I'm looking for a better design though and came to this post.
To unsubscribe from this group and all its topics, send an email to clean-code-discussion+unsub...@googlegroups.com.

Dave Schinkel

unread,
Aug 19, 2015, 11:30:50 PM8/19/15
to Clean Code Discussion
"Create interface gateways and you can use pure in memory object implementations."
 
Hey so are you using gateways AND repositories here?  Whereas gateways might be higher up in the layers and repositories closer to your DAL Facade?


On Saturday, January 24, 2015 at 2:34:51 PM UTC-6, gaz_edge wrote:
To unsubscribe from this group and all its topics, send an email to clean-code-discussion+unsub...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages