¿ªÔÆÌåÓý

ctrl + shift + ? for shortcuts
© 2025 Groups.io

Re: testing on the web


 

One reasonable way to get from a few slow-running end-to-end tests to some strategic unit testing is to do the following whenever you encounter a bug:

1. Once you have diagnosed the bug, verify your diagnosis with at least one unit test on the function/object/component that you believe is at fault.? If your diagnosis is good, then that test should fail before you fix the bug and pass after you fix the bug.? If it turns out that the fix is insufficient to fix the bug, figure out what else is wrong and write one or more tests for that failure.

This way, you avoid the compulsion/burden to cover the entire system with unit tests, instead just putting them where failures have been found (which makes those places more likely to have future failures than other random functions/objects/components of the system).? Accumulate these unit tests and run them frequently, since they are fast.

On Thu, Mar 10, 2022 at 10:26 AM Tim Ottinger <tottinge@...> wrote:
JB's done a great job here.

Selenium has its place, of course, but my usual heartburn is that you have to have a full system (even if some are mocks) stood up and then you have to do a lot of waiting for the next dialog/action/reaction to occur. That usually means that 1 selenium test takes longer to run than hundreds of what we might call "unit tests" or "microtests". If you're going from no tests to 'stand it up and test something' then that's not the most important consideration.

You could, of course, have a selenium?'setup' test (background, whatever you want to call it) that logs in once and you use the login for all your other selenium tests, but this is slow and tends to be more fragile and unfun than unit tests.

Following Joe's suggestions is a better path in general, I'd say.

In one recent app, we extracted a function for 'checkAuthn' so that we could override it with mocks. Then, rather than deal with tokens and the like, we tell that function to report the current user is (guest|author|admin|etc) and bypass the whole authentication/authorization thing. You might also make an overrideable?function for "is current user allowed to do this action": a mock returns 'yes' or 'no' depending on the need of your test.

You can get a lot of mileage out of "extract function so you can mock it" in proper micro/unit tests.



On Thu, Mar 10, 2022 at 10:38 AM Charlie Poole <charliepoole@...> wrote:
Joe... nicely put!


On Thu, Mar 10, 2022 at 6:20 AM J. B. Rainsberger <me@...> wrote:
On Tue, Mar 8, 2022 at 9:34 AM Alan Baljeu via <alanbaljeu=[email protected]> wrote:
I'm a desktop software developer getting into web development, using C# at present.? Also aiming to do Angular.? I'm fishing for strategies, techniques, tools I should be using to test stuff.? My current scenario is my application starts in a web browser, connects to my web server, requires the user to login (OAuth2) to a 3rd party service.? After login, the main path is for the browser to pose queries to my server, which it fulfills by using this 3rd party.

I can do all these things.? My confusion comes trying to write unit tests, integration tests, etc.? There is no user to login, so how does one get started?? Beyond that, I'm not greatly familiar with web stack software and so the fashion of doing TDD is also unfamiliar to me.? Can you guide me?? Can you point me to a guide?? Beyond NUnit, what do you recommend for testing my server?

First things first: if you can imagine an action and an expected result, then you have enough information to write a test. Start there. You will probably find that you write mostly end-to-end tests. This makes many programmers nervous because they read articles telling them not to do this. I advise you to ignore those articles for now, even though I've written some of them.

Instead, write any test that you know how to write. It will feel slow; let it feel slow.

Eventually you'll notice _specific aspects_ of your tests that you don't like. These will be the repeated annoyances that actually bother you right now. When you find those, ask us again for how to overcome them.

I can anticipate one such annoyance: login. When we add authentication, we have to change every end-to-end test to start with "user logs in", even when 90% of our tests don't actually care about a user logging in. Let me be clear: these are not tests that assume that we have an authenticated user; they are tests that prefer to ignore authentication entirely. The difference is largely theoretical, but it matters to me. I want to move such tests "under the skin", below the part of the system that wants to protect web pages from unauthorized access. These are no longer web site tests; they are some other kind of test. Accordingly, I want to write narrower/smaller tests (ones that run a smaller part of the system).

We call those "unit tests", because they treat a smaller part of the system as a self-contained unit. Other people have strange definitions of "unit test". You'll get used to it. :P

For now, it's enough to treat "unit tests" as "tests that talk _below_ the HTTP layer". They check the logic of the code without worrying about how we expose that logic over HTTP. Try to write such a test. How difficult is it to try a convincing test that doesn't even know that HTTP exists somewhere above it? That difficulty points to unhealthy dependencies in your design: code that doesn't need to know that it's running over HTTP, but that can't run without HTTP.

I want less of that code, for a variety of reasons. The most immediate reason for you is that it's easier to test code that doesn't even know that HTTP exists.

You can now also start from the inside out: find the parts of your code that already run entirely in memory (no HTTP, no files, nothing outside) and try to write tests for that code. Those tests might seem naive and useless, but you're practising writing tests (at all), so that's OK. Gradually you'll realize "this code would be easier to test if it ran entirely in memory... and I think I can make it do that". Make it do that.

I think this gives you a place to continue. What follow-up questions does it raise for you? Which questions does it settle for you?
--
J. B. (Joe) Rainsberger :: ?:: ::


--
J. B. (Joe) Rainsberger :: :: ::
Teaching evolutionary design and TDD since 2002



--
Peace,
Tim
-------------------------------------


Join [email protected] to automatically receive all group messages.