I have read so many places is that if your code is not test-able that mean code is not well written. So that makes me start writing a code that is test-able and to start using some unit testing framework.
With this though I start looking for some example with piece of code that is not testable and gradually converted to a testable code. I find tons of examples on unit testing but if someone can provide an example like above it probably can jump start things for me.
TIA
The term non-testable is used since, from the point of view of correctness testing, if one cannot decide whether or not the output is correct or must expend some extraordinary amount of time to do so, there is nothing to be gained by performing the test.
Tightly coupled code is extremely hard to unit test (and probably shouldn't be unit tested - it should be re-factored first), because by definition unit tests can only test a specific unit of something. All calls to databases or other components of the system should be avoided from Unit Tests because they violate this.
According to that line of reasoning, writing unit tests before writing code is a recommended way to do proper software engineering. Technically speaking, this "measure twice, cut once" approach is called a "test-first" approach.
Here are two great books that will help you get started:
Good luck.
Put a bunch of code in a button click event and try to unit test it. It's not impossible, but will either be non-trivial or require some copy-paste finagling to get it done.
protected void buttonClick(object sender, EventArgs e)
{
string currUser =
User.Identity.Name.ToString().Trim()
.Substring(User.Identity.Name.ToString().Trim()
.IndexOf("\\") + 1);
Inventory.Employee.DB objEmpDB = new Inventory.Employee.DB();
Inventory.Employee.Details objEmpDetails =
new Inventory.Employee.Details();
objEmpDetails = objEmpDB.Get(currUser);
Welcome.Text =
"Current User: " + objEmpDetails.Employee_Full_Name;
var objUserDetails = new Inventory.User.Details();
Inventory.User.DB objUserDB = new Inventory.User.DB();
if (objUserDB.UserAuthenticates(currUser))
{
objUserDetails = objUserDB.Get(currUser);
currUserToken = objUserDetails.User_Token.Value;
userID.Text = currUser;
if (objUserDetails.Active_User_Name != objUserDetails.User_Name)
{
lShadow.Text = "Showin: " + objUserDetails.Active_User_Name;
lServer.Text = "(" +
objUserDB.UserPermissionName(objUserDetails.Active_Logon_Name)
+ ") - " + System.Environment.MachineName;
lShadow.ToolTip = Inventory.Properties.Settings.Default
.connectionString.Substring(0, Inventory.Properties
.Settings.Default.connectionString.IndexOf(';'));
divShadow.Visible = true;
}
else
divShadow.Visible = false;
lWelcome.Text = "Current User: " + objUserDetails.User_Name;
}
}
Not only is this hard because of the difficulty of emulating a user button click, but look how much is going on in that button click. If your unit test fails, there's about 100 freakin things that could have gone wrong. DRY, single concern, and other design principles lead to code that's easy to test and easy to fix. After all, what good is a unit test if you are testing brigades rather than units :)
UPDATE: (How to fix the above code)
I'm not going to pretend that the code above is an easy fix. That's a "small" sample from a code base I've worked on in the past. I wanted to show how bad things can get in real life.
There's two major problems with the code.
Its easy to fix the Event driven/reproducing a button click event problem. You can wrap all that code into another method:
protected void buttonClick(object sender, EventArgs e)
{
EasyToCallMethod();
}
public void EasyToCallMethod()
{
string currUser =
User.Identity.Name.ToString().Trim()
.Substring(User.Identity.Name.ToString().Trim().IndexOf("\\") + 1);
//...rest of code
}
Now its easy to call from a unit test. But, that's a little silly because it really doesn't solve the second problem.
Easy Fix
So there's a good 15-20 tests that we can make out of this one method call. Just make a test for each line that has a specific purpose (like where method calls are made) and you should have good unit tests that are small enough to tell where something broke and good code coverage.
Advanced stuff
Much more work can be done. We can implement n-tier MVC or MVVM . At some point, you have to ask yourself if you are over-engineering. Unit tests should make your code more maintainable, but don't over-abstract yourself into nothingness. This is where your own style and experience come into play. When you feel like you've got the basics you should come back to SO with new questions or pickup a good book.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With