lessless
I wonder if it’s possible to mimic a simple “class reopening”/inhertinace-based SEAM in Elixir to alter a module’s behaviour without editing its code.
Here is an example in pseudo-Ruby
class PriceCalculator
def calculate_price(order)
base_price = calculate_base_price(order)
shipping = calculate_shipping(order)
base_price + shipping
end
def calculate_shipping(order)
ShippingServices.calculate_shipping(order)
end
end
Now the calculate_shipping is enabling point to override the shipping costs calculation behaviour because we can override it in tests without altering the production code.
class Test
class PriceCalculatorStub < Price calculator
def calculate_shipping(order)
1000
end
end
def test_order_price_is_base_price_plus_shipping_price
assert 1100 == PriceCalculatorStub.new.calculate_price(...)
end
end
Example is adapted from Legacy Seam
Trending in Discussions
A little off-topic, but I feel like people here have a good head on their shoulders.
I used to be quite good at making software. Was luc...
New
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
Hi there! :wave:
@frigidcode and I (but mostly him) have been running an Elixir Book club, we’re almost done with Designing Elixir Syste...
New
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with.
But I don’t use it anymore.
Serverless was the promis...
New
Lately I’ve been thinking about how to organize components as a LiveView application grows. One of the pain points I’ve found (for myself...
New
What IDE or editor are you using for Elixir development?
Personally, I use Zed, and I really like it, but sometimes I wish there were a ...
New
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
Other Trending Topics
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
In 2021 I started a new library called Tempo with the objective of modelling time as a set of intervals - not as instants. In 2022 I gave...
New
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly)
AI dream has many faces, but general...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #ai
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixirconf-us
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #security
- #performance











First Post!- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
D4no0
If my assumptions are correct, your
calculate_shippingdepends on an external API? If yes, then we universally use mocks for such external calls. There is Mox library that I personally always use and similar ones for doing this.Alternatively, if the things you want to mock in tests are very limited in their scope, you can inject your functions as parameters and later replace them in your tests:
Most Liked
sodapopcan
There’s also Efx. It’s a cool library. Personally I found myself going back to Mox, though (not that that matters).
LostKobrakai
There’s two parts here. There’s introducing the interface of the seam and there’s how to switch out the implementation.
For the first one the answer is quite simple. Extract to a function, make the function inputs and outputs the interface. We commonly use Behaviours for that stuff given things usually don’t just need a single callback.
The latter is dependency injection in whatever form you want to do it. Personally I like explicitly passing in dependencies (e.g.
GenServer.start_link(Dependency, …)is just that), but you can go withApplication.get_envor some other global dependency resolver option. For tests specificallyMoxwill allow you to use a single behaviour implementing module to inject dynamic code to run.I’d strongly suggest not getting hung up on the inheritance portion of this. It’s imo irrelevant to what that blog post tries to teach.
I’d also suggest to let loose of the “without altering the production code”. None of the examples of Martin Fowler left the production code untouched.
LostKobrakai
Imo that kind of thinking is a trap. You by definition now have at least two implementations, not one. It doesn’t matter that only one is used in production.
That’s fair. But I mentioned you don’t need to go the explicitly passing route. You can just as well start some global process somewhere, which provides the dependency to be used. Call that in your code and you don’t need callers of said code to change. Same with
Application.get_env. That’s also global state you can read without needing callers to be involved. The big piece here is “global state” no matter the technical implementation. The technical path chosen by Martin Fowler was global state through a static class variable.Last Post!
yordisprieto