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. They’re not for you. You’ll get there, but you don’t need to start there.
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 at the moment, rather than hypothetical problems you feel vaguely uneasy about. 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 might seem largely theoretical, but I ruthlessly remove irrelevant details from tests. Doing this helps me reduce the cost of maintaining my designs. 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 tests for the core behavior of the application. They have nothing to do with web technology. Accordingly, I prefer to write narrower/smaller tests to check that behavior, meaning tests 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”. It’s a long story. You’ll get used to it.
For now, you’d do well enough if you treated “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 for you right now to write a convincing test that doesn’t even know that HTTP exists? 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. (By coincidence, it’s also easier to convince yourself that it works without tests. Shhh.)
Not Only Outside-In, But Also Inside-Out
You can 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?