my algorithm practice with TDD - c#

Hello I am a newbie to TDD style programming in c# and am struggling a lot for getting it right. Could you please let me know if I am doing this in the right way. I have followed a lot of tutorials but haven't succeeded. I get the theory aspect of it but when it comes to putting it practically I always fail.
I have this repository for practising tdd https://github.com/dev-test-tdd/AlgorithmPractice/. I have started writing all the algorithms from scratch to understand tdd. For example , I have this simple method to check if the given string is a palindrome or not.
Here is my test
[Test]
public void IsPalindrome3Test()
{
var sourceString = "civic";
var result = Program.IsPalindrome3(sourceString);
Assert.AreEqual(true, result);
}
and the function
public static bool IsPalindrome3(string source)
{
int min = 0;
int max = source.Length - 1;
while(true)
{
if(min > max)
{
return true;
}
char a = source[min];
char b = source[max];
if(char.ToLower(a)!= char.ToLower(b))
{
return false;
}
min++;
max--;
}
}
Am I right here when writing the test ? Please let me know if the approach taken is right. Any pointers for that matter would be great !!

This isn't really TDD you're talking about. This is just a unit test. TDD refers specifically to the process of writing your tests before your code. You start out with the most trivial case, see the test fail, make it pass in the simplest way possible and then you impose some new assumptions by writing more tests. The point is that as your tests become more specific and cover more edge cases, the code becomes more generic.
There are many ways to do this and people prefer different levels of granularity. One version would be something like:
// Single character is always a palindrome
Assert.True(IsPalindrome("a"));
Which would prompt us to write the simplest possible code to make this pass
bool IsPalindrome(string input)
{
return true;
}
This code isn't "correct" though (although it's correct for all things we are testing for at the moment). We need more tests!
// Two non-equal characters are not a palindrome
Assert.False(IsPalindrome("ab"));
leading to
bool IsPalindrome(string input)
{
return input.Length == 1;
}
And so forth. Stepping through the whole process of implementing the full algorithm takes too long for an SO answer, I just want to show that it's an iterive process with short feedback loops where you constantly impose stronger and stronger assertions about how the code should work, and then you let the algorithm grow. There are plenty of videos on youtube about this, and books and blogs as well. Go check them out!
Last but not least, it's also important that we when our tests are passing make sure to "clean up" the code too. Making the code pass in the simplest way possible often leads to some ugly repetitions and such. When tests are passing we can refactor this while staying confident that our code still holds up to the assertions we made. It's important not to add more functionality when refactoring though, because then that functionality isn't written test first, which is the whole point of the endeavour.

Related

Do Guard Clauses Alone Require Unit Testing?

TLDR
Does this method require Unit Testing? If your answer is Yes, please ensure you understand my thought process by reading the whole Question.
public void UpdateChildSomethings(int parentId, string newVal, int bulkSize) {
var skip = 0;
List<Child> children = null;
while ((children = _.GetChildrenFromDB(parentId, skip, bulkSize)).Count > 0) {
var alteredChildren = AlterChildren(children, newValue); // Note: AlterChildren is fully tested separately.
_.BulkUpdateDB(alteredChildren);
skip += bulkSize;
}
}
Foreword
First off, I am a heavy Unit Tester. I do it often, and I do it well. But given my experience, I have gained opinions and may need somebody to put my in my place, or provide me with documentation to support or oppose me.
Opening Disclaimer: If I have an obviously tested method (Like Alter and AlterChildren below), and they have Guard Clauses in them, I'm probably going to end up testing the Guard Clauses, if for nothing more than 100% coverage in those tests. But apart from that...
The Question
Let's begin my question with this method:
public void UpdateSomething(int id, string newVal) {
var actualSomething = _.GetFromDB(id);
var alteredSomething = Alter(actualSomething, newVal);
_.UpdateDB(id, alteredSomething);
}
Does this method require Unit Testing? For multiple reasons, I would personally say no, at least not at this time. Especially if Alter() is abundantly tested. The action of Getting from DB and Updating DB have no value to Unit Test, and would be mocked anyway.
Assuming you follow my mindset and agree that method shouldn't be tested, what about this method?
public void UpdateSomething(int id, string newVal) {
var actualSomething = _.GetFromDB(id);
if (actualSomething == null) return;
var alteredSomething = Alter(actualSomething, newVal);
_.UpdateDB(id, alteredSomething);
}
I added a "Guard Clause". This is not business logic or calculation. It is code which determines the flow of code and early return. If I were to Unit Test this, I would essentially be testing the result of GetFromDB, and therefore be Testing a Mock. As far as I am concerned, Testing a Mock is not a useful test.
More Complex
But assuming you STILL follow my mindset and agree that Guard Clauses based on External Data is a waste to Unit Test, what about this method?
public void UpdateChildSomethings(int parentId, string newVal, int bulkSize) {
var skip = 0;
List<Child> children = null;
while ((children = _.GetChildrenFromDB(parentId, skip, bulkSize)).Count > 0) {
var alteredChildren = AlterChildren(children, newValue);
_.BulkUpdateDB(alteredChildren);
skip += bulkSize;
}
}
For clarity, I'll refactor this to break down the while clause
/// Uses parentId to retrieve applicable children in chunks of bulkSize.
/// children are processed separately.
/// Passes processed children to the DB to be updated.
public void UpdateChildSomethings(int parentId, string newVal, int bulkSize) {
var skip = 0;
List<Child> children = null;
while (true) {
children = _.GetChildrenFromDB(parentId, skip, bulkSize);
if (children.Count == 0) break;
var alteredChildren = AlterChildren(children, newValue);
_.BulkUpdateDB(alteredChildren);
skip += bulkSize;
}
}
At first glance, this looks complex enough to test, but what are you testing? Once again assuming that AlterChildren() is abundantly tested, the only thing left to test is the result of GetChildrenFromDB(), which is mocked. Once again Testing a Mock. The only line here doing something is skip += bulkSize. What would you be testing there, the += operator? I still don't see the point.
So, that is my most complex example, should it be Unit Tested?
The code in question here does not seem to contain any business logic. I think your point is: Should this be tested although it does not contain business logic and is fairly trivial?
There is nothing wrong with testing "mechanics" (as opposed to business logic). There is no reason you can only test business logic. UpdateSomething provides a service to other parts of the application. You have an interest in that service being performed correctly.
I do not quite see the difference between "guard clauses" and any other logic. It's behavior that is relevant to the functioning of the application.
You question whether logic based on external data is to be tested. I do not see this as a criterion either.
These things make it more likely that a test should be written: The code is easy to test; bugs have a high cost; quality is important for this piece of code; the test will not cause additional maintenance work; the test does not require much change to production code.
Act according to concrete criteria like that.
Update:
Can you update your answer, or comment, about whether or not you'd test the simplest code example I gave under "Let's begin my question with this method", and why/not?
Well, I can't say that because I don't know how valuable this is to test to you. If you have other tests that implicitly exercise this then I'd tend not to test it I guess. I'm personally not keen on writing tests for trivial things but I guess that's a matter of personal experience. Really, I feel that the criteria you proposed in the question have no intrinsic bearing on the decision at all. The decision should be made according to the criteria I set forth. This means that I lack the knowledge to come to a decision.
In my career I have found time and time again that programming by rules does not work. Programming is like chess - it is infinitely complex. No set of rules can adequately make decisions for you. Rather, develop a mental toolbox of heuristics and patterns to guide you in the concrete case. In the end you must decide based on the concrete case as a whole, not based on a rigid rule. That's why I said "these things make tests more likely", not "you should test when...".
That's why rules such as "test getters and setters" or "do not test getters and setters" are simply false! Sometimes you test them, sometimes you don't.
Your code is a combination of computations and interactions. The value of unit-testing such code often appears questionable a) due to the effort for mocking and b) due to the resulting dependency of the unit-tests on implementation details. One approach that often helps is to modify the code in a way that the computations and interactions are separated into different functions/methods. Functions with computations are then tested using unit-testing with no or at least reduced need for mocking, and interaction dominated functions are tested with integration testing.
In your example, a possible separation between computations and interactions could look as shown below:
public int BulkUpdateChildren(int parentId, string newVal, int skip, int bulkSize) {
List<Child> children = _.GetChildrenFromDB(parentId, skip, bulkSize);
if (children.Count > 0) {
var alteredChildren = AlterChildren(children, newValue);
_.BulkUpdateDB(alteredChildren);
}
return children.Count;
}
public void UpdateChildSomethings(int parentId, string newVal, int bulkSize) {
var skip = 0;
var updated;
do {
updated = BulkUpdateChildren(parentId, newVal, skip, bulksize);
skip += updated;
} while (updated == bulksize);
}
The new method BulkUpdateChildren contains all the interactions with the dependencies - this would best be tested using integration testing. What remains within UpdateChildSomethings is computation dominated, and testing it only requires to mock one single method within the SUT itself, namely the call to BulkUpdateChildren. Unit-testing UpdateChildSomethings is therefore easier and can focus on the question whether in all possible cases the value of skip is updated properly and if the loop terminates as expected.
There is only very little logic left within BulkUpdateChildren, namely the check whether there were any children found, and the 'computation' of the return value. Maybe the check for zero children is even unnecessary (unless for performance reasons), if the methods AlterChildren and BulkUpdateDB are able to deal with empty lists. When leavin this check out, this code would consist almost only of interactions:
public int BulkUpdateChildren(int parentId, string newVal, int skip, int bulkSize) {
List<Child> children = _.GetChildrenFromDB(parentId, skip, bulkSize);
var alteredChildren = AlterChildren(children, newValue);
_.BulkUpdateDB(alteredChildren);
return children.Count;
}

How to verify number of calls method of 'this' service

I'm using NUnit framework with moq for testing. I've got a problem with veryfing how many times private method of this class has been called. To do so with mock object it's enough to call Verify() with parameters of type Times, but my method is part of this class. I was trying to mock current service (SUT), but it probably isn't the best idea and it doesn't work properly.
SUT:
public object Post(Operations.Campaign.Merge request)
{
List<CampaignIdWithNumberOfAds> campaignList = new List<CampaignIdWithNumberOfAds>();
for (int i = 0; i < request.CampaignIdsToMerge.Count; i++)
{
if (this.CampaignRepository.Exist(request.CampaignIdsToMerge[i]))
{
campaignList.Add(new CampaignIdWithNumberOfAds()
{
CampaignId = request.CampaignIdsToMerge[i],
NumberOfAdvertisement = this.CampaignRepository.GetNumberOfAdvertisementsInCampaign(request.CampaignIdsToMerge[i])
});
}
}
if (campaignList.Count > 1)
{
campaignList = campaignList.OrderByDescending(p => (p == null) ? -1 : p.NumberOfAdvertisement).ToList();
List<CampaignIdWithNumberOfAds> campaignsToMerge = campaignList.Skip(1).ToList();
CampaignIdWithNumberOfAds chosenCampaign = campaignList.FirstOrDefault<CampaignIdWithNumberOfAds>();
uint chosenCampaignId = chosenCampaign.CampaignId;
foreach (var campaignToMerge in campaignsToMerge)
{
this.MergeCampaigns(chosenCampaignId, campaignToMerge.CampaignId);
}
}
return true;
}
Test:
[Test]
public void MergeCampaignsPost_ValidMergeCampaignsRequest_ExecuteMergeCampaignsMethodAppropriateNumberOfTimes()
{
// Arrange
var mockCampaignService = new Mock<Toucan.Api.Services.CampaignService>();
var request = Mother.GetValidMergeCampaignsRequest_WithDifferentNumbersOfAdvertisement();
mockCampaignService.Setup(x => x.MergeCampaigns(It.IsAny<uint>(), It.IsAny<uint>()));
// Act
var response = this.Service.Post(request);
// Assert
mockCampaignService.Verify(x => x.MergeCampaigns(It.IsAny<uint>(), It.IsAny<uint>()), Times.Exactly(request.CampaignIdsToMerge.Count - 1));
}
I am afraid that I won't give you a solution here, although I would rather suggest you some sort of guidance. There are many different strategies to unit testing and different people would suggest different solutions. Basically in my opinion you could change the way you are testing your code (you might agree or disagree with those, but please take them into consideration).
Unit test should be independent from the implementation
Easy as it sounds, it is very hard to keep to this approach. Private methods are your implementation of solving the problem. The typical pitfall for a developer writing a unit test for his own code is the fact that you know how your code works and mirror it in unit test. What if the implementation changes, but the public method will still fulfill the requested contract? Hardly ever you want to directly your unit test with a private method. This is related to the following...
Test should check the output result of the method
Which basically means do not check how many times something is executed if you don't have to. I am not sure what is your MergeCampaigns method doing but it would be better if you check the result of the operation instead of how many times it is executed.
Don't overdo your unit tests - keep it maintainable
Try to test each functional scenario you can imagine with as simple and as independent test as possible. Don't go too deep checking if something is called. Otherwise, you will get a 100% coverage at start, but you will curse each time changing a thing in your service, because this will make half of your test fail (assuming that the service is still doing its job, but in different way than designed at the beginning). So you will spend time rewriting unit tests that actually give you no gain in terms of creating a bulletproof solution.
It is very easy to start writing unit tests and keep the coverage green, it starts to get very tricky if you want to write good unit tests. There are many valuable resources to help with that. Good luck!

Are heading comments recommended when unit testing with Arrange-Act-Assert?

I find the concept of partitioning the statements of my unit tests as suggested in the AAA pattern useful.
I tend to add heading comments so that the tests look like this:
// Arrange
int a = 1;
int b = 2;
// Act
int c = a + b;
// Assert
Assert.AreEqual(3, c);
But I am curious, is it normal to always include these header comments?
...or is this something which I should avoid?
int a = 1;
int b = 2;
int c = a + b;
Assert.AreEqual(3, c);
That doesn't seem to add much value once the basic premise is understood. Since you mention C#, I suggest taking a look at The Art of Unit Testing for examples. Naming a unit test correctly is more important IMHO than arrange/act/assert comments within it. As the book points out, when a test fails, if it is named well you can often deduce the cause of a regression directly if you know what changes were made recently.
I've gotten a lot of value out of doing this. It (to me) looks cleaner, is immediately clear which parts of the test are doing what, and it somewhat enforces the pattern. So no, I don't think you need to avoid it.
If your tests are getting really complicated that's a separate issue. Even a six line test can benefit from those comments. If you have no assert section because you're checking that an exception is thrown, then obviously don't include the assert comment.
I'm always thankful to have those in code that I'm reviewing, particularly for integration tests. I feel it saves me time.

Unit testing a class that generates distinct strings

I'm trying to write a unit test for a class that generates distinct strings. My initial reaction was the following:
public void GeneratedStringsShouldBeDistinct()
{
UniqueStringCreator stringCreator = new UniqueStringCreator();
HashSet<string> generatedStrings = new HashSet<string>();
string str;
for (int i = 0; i < 10000; i++)
{
str = stringCreator.GetNext();
if (!generatedStrings.Add(str))
{
Assert.Fail("Generated {0} twice", str);
}
}
}
I liked this approach because I knew the underlying algorithm wasn't using any randomness so I'm not in a situation where it might fail one time but succeed the next - but that could be swapped out underneath by someone in the future. OTOH, testing of any randomized algorithm would cause that type of test inconsistency, so why not do it this way?
Should I just get 2 elements out and check distinctness (using a 0/1/Many philosophy)?
Any other opinions or suggestions?
I would keep using your approach; it's probably the most reliable option.
By the way, you don't need the if statement:
Assert.IsTrue(generatedStrings.Add(str), "Generated {0} twice", str);
If I wanted to test code that relied on random input, I would try to stub out the random generation (say, ITestableRandomGenerator) so that it could be mocked for testing. You can then inject different 'random' sequences that appropriately trigger the different execution pathways of your code under test and guarantee the necessary code coverage.
The particular test you've shown is basically a black box test, as you're just generating outputs and verifying that it works for at least N cycles. Since the code does not have any inputs, this is a reasonable test, though it might be better if you know what different conditions may impact your algorithm so that you can test those particular inputs. This may mean somehow running the algorithm with different 'seed' values, choosing the seeds so that it will exercise the code in different ways.
If you passed the algorithm into UniqueStringCreator's constructor, you could use a stub object in your unit testing to generate psuedo-random (predictable) data. See also the strategy pattern.
If there's some kind of check inside the class, you can always separate out the part which checks for distinctness with the part that generates the strings.
Then you mock out the checker, and test the behaviour in each of the two contexts; the one in which the checker thinks a string has been created, and the one in which it doesn't.
You may find similar ways to split up the responsibilities, whatever the underlying implementation logic.
Otherwise, I agree with SLaks - stick with what you have. The main reason for having tests is so that the code stays easy to change, so as long as people can read it and think, "Oh, that's what it's doing!" you're probably good.

Unit Testing with functions that return random results

I don't think that this is specific to a language or framework, but I am using xUnit.net and C#.
I have a function that returns a random date in a certain range. I pass in a date, and the returning date is always in range of 1 to 40 years before the given date.
Now I just wonder if there is a good way to unit test this. The best approach seems to be to create a loop and let the function run i.e. 100 times and assert that every of these 100 results are in the desired range, which is my current approach.
I also realize that unless I am able to control my Random generator, there will not be a perfect solution (after all, the result IS random), but I wonder what approaches you take when you have to test functionality that returns a random result in a certain range?
Mock or fake out the random number generator
Do something like this... I didn't compile it so there might be a few syntax errors.
public interface IRandomGenerator
{
double Generate(double max);
}
public class SomethingThatUsesRandom
{
private readonly IRandomGenerator _generator;
private class DefaultRandom : IRandomGenerator
{
public double Generate(double max)
{
return (new Random()).Next(max);
}
}
public SomethingThatUsesRandom(IRandomGenerator generator)
{
_generator = generator;
}
public SomethingThatUsesRandom() : this(new DefaultRandom())
{}
public double MethodThatUsesRandom()
{
return _generator.Generate(40.0);
}
}
In your test, just fake or mock out the IRandomGenerator to return something canned.
In addition to testing that the function returns a date in the desired range, you want to ensure that the result is well-distributed. The test you describe would pass a function that simply returned the date you sent in!
So in addition to calling the function multiple times and testing that the result stays in the desired range, I would also try to assess the distribution, perhaps by putting the results in buckets and checking that the buckets have roughly equal numbers of results after you are done. You may need more than 100 calls to get stable results, but this doesn't sound like an expensive (run-time wise) function, so you can easily run it for a few K iterations.
I've had a problem before with non-uniform "random" functions.. they can be a real pain, it's worth testing for early.
I think there are three different aspects of this problem that you test.
The first one: is my algorithm the right one? That is, given a properly-functioning random-number generator, will it produce dates that are randomly distributed across the range?
The second one: does the algorithm handle edge cases properly? That is, when the random number generator produces the highest or lowest allowable values, does anything break?
The third one: is my implementation of the algorithm working? That is, given a known list of pseudo-random inputs, is it producing the expected list of pseudo-random dates?
The first two things aren't something I'd build into the unit-testing suite. They're something I'd prove out while designing the system. I'd probably do this by writing a test harness that generated a zillion dates and performed a chi-square test, as daniel.rikowski suggested. I'd also make sure this test harness didn't terminate until it handled both of the edge cases (assuming that my range of random numbers is small enough that I can get away with this). And I'd document this, so that anyone coming along and trying to improve the algorithm would know that that's a breaking change.
The last one is something I'd make a unit test for. I need to know that nothing has crept into the code that breaks its implementation of this algorithm. The first sign I'll get when that happens is that the test will fail. Then I'll go back to the code and find out that someone else thought that they were fixing something and broke it instead. If someone did fix the algorithm, it'd be on them to fix this test too.
You don't need to control the system to make the results deterministic. You're on the right approach: decide what is important about the output of the function and test for that. In this case, it is important that the result be in a range of 40 days, and you are testing for that. It's also important that it not always return the same result, so test for that too. If you want to be fancier, you can test that the results pass some kind of randomness test..
Normaly I use exactly your suggested approach: Control the Random generator.
Initialize it for test with a default seed (or replace him by a proxy returning numbers which fit my testcases), so I have deterministic/testable behaviour.
If you want to check the quality of the random numbers (in terms of independance) there are several ways to do this. One good way is the Chi square test.
Sure, using a fixed seed random number generator will work just fine, but even then you're simply trying to test for that which you cannot predict. Which is ok. It's equivalent to having a bunch of fixed tests. However, remember--test what is important, but don't try to test everything. I believe random tests are a way to try to test everything, and it's not efficient (or fast). You could potentially have to run a great many randomized tests before hitting a bug.
What I'm trying to get at here is that you should simply write a test for each bug you find in your system. You test out edge cases to make sure your function is running even in the extreme conditions, but really that's the best you can do without either spending too much time or making the unit tests slow to run, or simply wasting processor cycles.
Depending on how your function creates the random date, you may also want to check for illegal dates: impossible leap years, or the 31st day of a 30-day month.
Methods that do not exhibit a deterministic behavior cannot be properly unit-tested,as the results will differ from one execution to another. One way to get around this is to seed the random number generator with a fixed value for the unit test. You can also extract the randomness of the date generation class (and thus applying the Single Responsibility Principle), and inject known values for the unit-tests.
I would recommend overriding the random function. I am unit testing in PHP so I write this code:
// If we are unit testing, then...
if (defined('UNIT_TESTING') && UNIT_TESTING)
{
// ...make our my_rand() function deterministic to aid testing.
function my_rand($min, $max)
{
return $GLOBALS['random_table'][$min][$max];
}
}
else
{
// ...else make our my_rand() function truly random.
function my_rand($min = 0, $max = PHP_INT_MAX)
{
if ($max === PHP_INT_MAX)
{
$max = getrandmax();
}
return rand($min, $max);
}
}
I then set the random_table as I require it per test.
Testing the true randomness of a random function is a separate test altogether. I would avoid testing the randomness in unit tests and would instead do separate tests and google the true randomness of the random function in the programming language you are using. Non-deterministic tests (if any at all) should be left out of unit tests. Maybe have a separate suite for those tests, that requires human input or much longer running times to minimise the chances of a fail that is really a pass.
I don't think Unit testing is meant for this. You can use Unit testing for functions that return a stochastic value, but use a fixed seed, in which case in a way they are not stochastic, so to speak,
for random seed, I dont think Unit testing is what you want, for example for RNGs what you mean to have is a system test, in which you run the RNG many many times and look at the distribution or moments of it.

Categories