-
Notifications
You must be signed in to change notification settings - Fork 157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: NUnit on-ramp minibook #745
base: master
Are you sure you want to change the base?
Conversation
Leaving off here for a little bit. I left off on this challenge: I'd created some projects in the Snippets solution with the intent of building a small supermarket checkout system to demonstrate the evolution into state control, mocking, etc. The challenge is: I want to show how these things evolve, but snippets can only pull from a file's current state. So I can't really do something like the Santa Sleigh blog post I did, because it's not in its own repo where I can reference the commits and trying to do so would be messy. So my choices are: write the code right in the markdown, or structure the snippets project so that there a lot of duplicate classes and structure so that I can pick the appropriate point-in-time snippet for the docs. This is further complicated because I can't just append For now I'm leaning toward writing the code in markdown to get it to a good place (copying from VS), and then extracting into the snippets project once it feels more settled, to at least avoid some of the confusion. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great structure and setup. Love this!
|
||
Different types of tests have different trade-offs in their usage. | ||
|
||
Typically, automated tests are thought of as a pyramid or a funnel. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might deserve a separate heading "The Test Triangle/Pyramid", and a figure would also be nice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely, that's in the plan 👍
|
||
## SUT / CUT (Situation/Class Under Test) | ||
|
||
You might hear the term `SUT` or `CUT` or see these variables in tests you come across. Typically they mean the situation or class under test. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am pretty sure the acronym stands for "System Under Test"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that it needs to, and I've commonly taught it as situation because it helps students get in the mindset of thinking what they're actually testing, in which case system may be entirely too broad or confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, https://glossary.istqb.org/en_US/search?term=SUT and also https://acronyms.thefreedictionary.com/SUT. I don't think it is wrong to use situation, but I would add System to the list there. It makes it inline with what I think is a more common use of the acronym
|
||
Like many things, this is a balance that a team should attempt to find and actively maintain. Some parts of tests can be extracted into common methods; other abstractions might make tests too hard to understand. Be willing to re-evaluate these choices as projects evolve. | ||
|
||
## Test Coverage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with this, but would add some specifics: Test Coverage should only include coverage of the production code, and not include the test code. If you do, e.g. then removing redundant test code will actually seem to reduce code coverage. The other also applies. Adding test code increases code coverage. This is part of what makes code coverage numbers very unreliable. That said, concentrate on covering complex code. It can be good here to mention the CRAP index. https://blog.ndepend.com/crap-metric-thing-tells-risk-code/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this because it surfaces something that is a natural part of how I think but wouldn't be for others. I'll consider adding a section on "what do we test?" Noting that we want to test production code and want to avoid our tests mimicking production code with a lot of logic that itself can fail.
@@ -0,0 +1,88 @@ | |||
# Testing Concepts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be wise here to include Shift-Left as a core testing principle. That is what you often want to do when refactoring systems. I would also stress that there is "war" between top level testing and low level testing. Even if you shift left, then you should NOT abandon your integration tests, just make sure that the bottom of your pyramid is rock solid. Imho the concept of test levels is even better than the triangle/pyramid. E.g. https://learn.microsoft.com/en-us/devops/develop/shift-left-make-testing-fast-reliable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By introducing shift-left, it is also easy to explain why testing these days is actually moving into the editors, and why Live Unit Testing has appeared. The Shift-left thinking explains a lot of why testing have been moving forward as it has.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely. Love it. For me that's built into thinking about "smaller loops" but it deserves its own callout.
|
||
These are typically meant as the "lowest level" of automated tests. They aim to test a specific, isolated class. Any dependencies that class has on other classes would be faked in unit tests, so that they can execute quickly and with a clear understanding of how the class will behave. There will be more on this later when we discuss [test doubles and mocks](TODO). | ||
|
||
## Integration Tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would define integration tests as tests that go outside the component itself and touches external components, e.g. databases, and in particular these days - external APIs. That means that complex unit tests, that cover more than just a few classes fall out of this, and I normally have called them Component Tests, tests that also might use integration test frameworks (like the asp net core one), but restrict the testing to the component itself, mocking everything outside the component.
The definition of a component may of course vary, but I often teach that "it all depends" and you might look at a VS solution as a component if the parts are just that, parts that make up a whole, OR you might consider each dll/csproj as its own component. The latter I normally teach can be hard to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw, the article https://learn.microsoft.com/en-us/devops/develop/shift-left-make-testing-fast-reliable introduce the "levels", and I have used that much more than just the naming. So you might have integration tests separated into different levels, depending upon how much they actually touch. Component tests would then just be a lower level of an integration test. This makes a lot of sense when you start to integrate these into CI/CD build systems, and have to decide which tests are to be run where.
|
||
So, the question becomes -- who will benefit from NUnit's particular _flavor_ of test framework? | ||
|
||
* NUnit benefits in particular from its longevity -- our first NuGet package was published in 2011, 13 years prior to this article being written. In that time, the library has amassed 200+ million downloads and has seen a ton of support from the community. To borrow the Farmers Insurance ad campaign, "We know a thing or two because we've seen a thing or two." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NUnit dates back to 1998 (I think), but picked up speed around 2002 with NUnit 2.2. That means actually 25 years of experience :-)
So, the question becomes -- who will benefit from NUnit's particular _flavor_ of test framework? | ||
|
||
* NUnit benefits in particular from its longevity -- our first NuGet package was published in 2011, 13 years prior to this article being written. In that time, the library has amassed 200+ million downloads and has seen a ton of support from the community. To borrow the Farmers Insurance ad campaign, "We know a thing or two because we've seen a thing or two." | ||
* We think that beginners and newcomers benefit from the _explicitness_ of NUnit and the way it approaches tests with attributes such as `[Test]`, `[SetUp]`, and `[TearDown]`. In some cases, xUnit relies on C# conventions in ways that might not be familiar. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very much agree. Also the "broadness", like the ability to add messages to Asserts (not in XUnit), the easy syntax for data-driven tests (TestCase, TestCaseSource), and extensibility - something that is not so much known, see a later section for more info :-)
|
||
* `Microsoft.NET.Test.Sdk` brings the test platform along and allows tests to be run using the `dotnet test` command. It's a good idea to add this to any .NET automated test project. | ||
* `NUnit` brings in the core NUnit library. | ||
* `NUnit3TestAdapter` surfaces NUnit3 tests for the Visual Studio / `dotnet test` runner. It essentially allows NUnit tests to be discovered. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It essentially allows NUnit tests to be discovered.
It essentially allows NUnit tests to be executed.
(Discovery may or may not be happening with the adapter, so its main focus is to handle the execution)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, thanks 👍
var result = sut.ConvertCToF(37); | ||
|
||
// Assert | ||
Assert.That(result, Is.EqualTo(98.6)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is a decimal, the result may or may not match. A good time to use the Within
Assert.That(result, Is.EqualTo(98.6).Within(0.1);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, technically. I think that gets into docs territory or another example scenario though. As is the test passes and AFAIK will always pass. Too many concepts to introduce for a "first use".
Though I do think it speaks to the need for a "common pitfalls and remedies" article that maybe briefly delves into summarizing some of the analyzer checks and additional things to watch for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, when doubles are used in particular one should be aware that the EqualTo may not match, decimals I think are better, but not quite sure. It all depends. Perhaps have a pointer to a Tricks and Traps section for that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Going for it. No time like the present. I imagine this will be in progress for a little while 😅
Thoughts & feedback always welcome via comments as I go.
Supports #706.
Remaining Work I don't want to Forget about
/book