Welcome to the 6th iteration of WebCalc. Previously I was dealing mostly with adding some more complex calculations. Like I mentioned there already, I think that I have already enough business logic to start moving into other areas like billing or user management. I also said that I’d be going into the unknown. Up until now, I had a rough idea of how to do things, now I don’t, I’ll be exploring a lot.
Ultimately I want the application to bill the users, every operation should cost them some money and at the end of a month, an invoice will be prepared. Writing such a test now would make me work in red for days. I think, that the simplest test now would be to disallow anonymous users from doing any calculations, only logged in users can do something. That means, that I need to actually change my integration tests and add some test user there plus write a test that verifies that the system refuses to work without being logged in first.
There are many ways how users can authenticate themselves, but to keep things simple I’d go for Basic Authentication. All those OAuth, OpenID or X509 are maybe more secure, can do more, but all that comes with much higher complexity. Long story short, username and password would need to be transferred on every request. That means that I also don’t need any logging in functionality or page. That would also mean that I should be using HTTPS only.
My new test will be very simple, I’ll just do the call without providing any authentication data and I’ll expect to get HTTP 401 in return, like so:
It fails because the HTTP status is still 200. I will already fix other tests to provide authentication data:
Time to include Spring Security in the project:
Apparently, Spring Boot does most of the stuff for me the moment it sees Spring Security JAR on the classpath. My new test is already passing, all others are red. To get them working I need to do a few things. First, I need to “add” a default user to Spring Security’s UserDetailsService:
I also need to configure the security a little. By default, Spring requires a correct CSRF token, but with basic auth only that doesn’t make much sense:
Now all my tests are once again green. So far so good, three small steps and I get my application secured. Sure, I only have one user and I’m not using HTTPS, so those things will require additional effort, but still. Can I unit test the thing that I just did? Unfortunately, it doesn’t seem possible and that’s making me feel uneasy, but let’s see how all this unfolds.
I don’t see the need right now to go deeper into user management or creating different users. All that would only be necessary once I start billing them for using the system. And that is, honestly, the only reason I can think of right now why I need any authorization anyway. So let’s go there. The idea is pretty simple, for every operation there’s a price, so after each calculation is done I’ll be adding its cost to the user’s bill. Of course, different functions will have different prices and each usage of a function will be charged, for example for calculating
1+2+3 you’d be charged twice for using sum.
One of the most interesting features for the users would be checking their current balance. I’ll not surprise anybody by exposing this via REST. This would also give me a possibility to verify later on charging proper users with correct amounts. This requires a new endpoint because it’s something else than calculations. It doesn’t belong to the app module, it should get its own eventually, but let’s start simple, I’ll extract it later. A test will look something like this:
The first thing that I’ve noticed was inconsistent naming for test classes. I’m still not sure if it’s a blessing or a curse. On one hand, such inconsistencies affect readability or understandability of the code and, in effect, lead to errors in the code. On the other hand, going for nothing less than perfection is most likely not helping me deliver business value. In this case, it’s a few renames, so let’s do it.
RestApiTest class will now be known as
CalculatorRestApiShould. The idea with test classes ending with
should is that when you read class name together with method names inside, they tell “a story”. I’ve learned it from Sandro Mancuso and it does make sense.
CaclulatorShould is already following this concept,
CalculatorRestApiShould not yet, so:
Back to the new API. The test is obviously red because I don’t have the controller yet. That’s easy to fix:
I should now push returning
0 down to some kind of service, for example:
Now things get much more interesting. Next logical step is to define a price for a function, execute a calculation using this function and see, that the balance increased. I’ll still blissfully ignore the existence of different users. I can also still get away with not persisting anything “for real”. The tricky part is, that I want the calculator to be completely unaffected by billing, the module should not depend on the billing module. Obviously, billing would need to depend on the calculator. I can quite easily achieve this with a decorator pattern. But before I go in there, I need a test:
Looks simple enough, but I don’t have
calculator. I need to create a
BillingCalculator, that will be a decorator of a “real” calculator, it will look like this:
For now the only thing it can is to delegate a call to another calculator that was passed into it. This other calculator might be an actual calculator, the one I’ve been writing so far, but it could also be a mock or anything else that can behave like a calculator. I’ll go yet again simple and use the real one. The fixed test looks like this:
The test now compiles, but is red, no surprises here. The problem here is that
BillingCalculator are completely separated from one another, yet somehow the information about executed calculations needs to flow between them. For a split second I was thinking about some common repository for the two, but luckily I don’t need that. If I pass
BillingCalculator, the latter can inform the former about all important things. Then the implementation could look like:
Of course, there’s still a lot of faking, but the tests are green, and that’s what I’m after. One note, I’m not going to be testing
BillingCaclculator separately, it’s part the whole billing module contract. Having separate tests for this class could make my life harder later on. Given the amount of faking I already did, sooner or later I’ll need to refactor the code. Having tests only going through the actual API of a module means that the inner structure of a module is completely irrelevant. That’s how I understand unit testing.
Little intermission here. As you might have noticed this iteration 6 is published long after iteration 5. I’m sorry about that. But you can also see what I’ve been working on in the meantime – the blog is no longer hosted on blogger.com, but rather GitHub Pages, built using Hugo and available through my own domain. There’s more than that, but maybe that’s something for another time and place.
That pause made me go back and take a look at what I’ve done so far in this iteration, and I’ve found a problem. The decorator is a wrong pattern to use in here. Using it I only see the interaction between
Calculator twice, once when
CalculatorController calls the
Calculator and once when the
Calculator returns a result. That’s not enough. That means that the billing would need to also parse each expression and count all the operations by itself. That was my original thinking, as far as I can remember, but now I believe I should be using observer pattern. I was thinking for a short time about creating two implementations and compare them at the end, but that would probably be too much.
So I’m going back to commit commit 579a1018 and start over. Those two commits with the usage of the decorator pattern I’ve pushed to the decorator branch. This time it will not be possible to avoid any changes in the
Calculator, but those changes will not be binding the module to anything, rather providing hooks from where interested parties could get the information they need. I have already one failing test in
BillingShould, that’s good.
I need a
calculator and I need to register my
billing as an observer, seems easy:
Now I need to do two things, add
addObserver method to
Calculator that would be taking something implementing a new
CalculatorObserver interface and make
Billing implement that interface. Let’s start with the
For simplicity, I’m now assuming that there can be only one observer. I can extend it later if need be. Also, the interface doesn’t do anything just yet, but at least the compilation error is gone so I can run the tests again. Sure enough, one is still red.
Because the test is written in such a way that it doesn’t matter what is being evaluated, the simplest thing that could possibly work could look like this:
And I’ll conclude this iteration here so that I can finally publish it. The original plan was to make every iteration out of one tomato of implementation plus then writing a blog post. Obviously, it doesn’t work, mostly because I’m writing code in parallel to post itself so that I can share my thoughts. But I will try to keep next iterations shorter, but publish them more often. Anyway, next time I’ll be finishing tests for billing and making the implementation follow. I’ll maybe also separate billing module from the app itself. See you next time!