So I came up with this lightweight library to help enforce unit tests with a Given-When-Then structure. I hope you find this useful. Any feedback are welcome.
https://github.com/cobrakai-lab/Cobrakai.GWTUnit
1–10 of 19 posts
So I came up with this lightweight library to help enforce unit tests with a Given-When-Then structure. I hope you find this useful. Any feedback are welcome.
https://github.com/cobrakai-lab/Cobrakai.GWTUnit
[TestMethod]
public void ShouldBeAbleToTestActions()
{
var dwarfs = new List() { "Sneezy", "Bashful", "Sleepy", "Happy", "Grumpy", "Doc", "Dopey" };
Action> DoDarkMagic = (creatures) => { creatures.RemoveAt(0); }
DoDarkMagic(dwarfs)
Should("have less dwarfs", () => { dwarfs.Count.Should().Be(6); });
Should("missing Sneezy", () => { dwarfs.Should().NotContain("Sneezy"); });
};I'm designing an internal library myself that does the same thing using Kotlin's EDSL support (you can specify the "this" type of a function) and splits test logic up into required, act, and provided blocks. E.g.
required {
// will be made true for test
check(something)
}
act {
// the act under test
click(someButton)
}
provided {
// will be verified for test
check(something)
}
The interesting thing here is that the polarity of the required and provided blocks can be flipped (check the required is true, and if it is make the provided true) to do fakes/mocks. Well, it is still something I'm working on. [Fact(Skip = "Generated With Snippet")]
public async Task MyTestMethodAsync()
{
//Arrange
//Act
//Assert
throw new NotImplementedException();
}
If that results in hard to read unittests I suspect that your library would too, as it is a matter discipline. If we assume that we use your terms, "Given, When, Then" in place of "Arrange, Act, Assert" - can you give an argument that would favour your solution with the syntactic overhead of putting it all in lambdas?What benefit do these abstractions give me over simply coding an Arrange/Act/Assert?
This seems a bit too fluent, but most Testing APIs for Java and C# seem to be heavily into fluent styles (everyone else seems to avoid them). I'm designing an internal library myself that does the same thing using Kotlin's EDSL support (you can specify the "this" type of a function) and splits test logic up into required, act, and provided blocks. E.g. required { // will be made true for test check(something) } act {…
My teams use a snippet that expands to the following [Fact(Skip = "Generated With Snippet")] public async Task MyTestMethodAsync() { //Arrange //Act //Assert throw new NotImplementedException(); } If that results in hard to read unittests I suspect that your library would too, as it is a matter discipline. If we assume that we use your terms, "Given, When, Then" in place of "Arrange, Act, Assert" - can you give an ar…
I also prefer AAA tests, but I can't stand it when people leave those comments in as some kind of region markers. IMO, they're useful when teaching AAA tests, but it seems, in my experience, most developers actually have those comments in every. single. test. That's some hardcore cargo culting.
I just use a blank line to separate the different stages, and if you have problems making that readable, you probably need to refactor the Arrange or Assert parts to use some helper methods.
I realize I'm probably overreacting, but I feel the anger rising whenever I see this in the wild (and have to suppress it).
My teams use a snippet that expands to the following [Fact(Skip = "Generated With Snippet")] public async Task MyTestMethodAsync() { //Arrange //Act //Assert throw new NotImplementedException(); } If that results in hard to read unittests I suspect that your library would too, as it is a matter discipline. If we assume that we use your terms, "Given, When, Then" in place of "Arrange, Act, Assert" - can you give an ar…
Vs "arrange a csv with a missing column act read it assert the exception contains the missing column name"
to be honest, I'd much prefer this [TestMethod] public void ShouldBeAbleToTestActions() { var dwarfs = new List () { "Sneezy", "Bashful", "Sleepy", "Happy", "Grumpy", "Doc", "Dopey" }; Action > DoDarkMagic = (creatures) => { creatures.RemoveAt(0); } DoDarkMagic(dwarfs) Should("have less dwarfs", () => { dwarfs.Count.Should().Be(6); }); Should("missing Sneezy", () => { dwarfs.Should().NotContain("Sneezy"); }); };
Action> DoDarkMagic = (creatures) => { creatures.RemoveAt(0); }
DoDarkMagic(dwarfs)
There is no point in putting the action in a variable, only to invoke it on the next line. This is a meandering way of expressing: // Do Dark Magic
dwarfs.RemoveAt(0);
Extract a private method if you're keen on keeping the name.The examples look like a lot more work. The ingredients and naming those into tuple variables, having to return the tuple type itself, three lambdas in there. What benefit do these abstractions give me over simply coding an Arrange/Act/Assert?
Tests in larger c# projects are often a mess.
People then turn to BDD or frameworks like to this to try to impose order.
Sometimes they produce better tests the second time around, but more often the additional overhead of the framework just means that "now you have 2 problems".
Probably no benefit, IMHO. Work on your tests, but avoid "high concept" frameworks.