I was going through this post related to handling of nulls.
One of the recommendation (as per the SO post) is to use Assert when nulls are not valid.
I have (so far) used nulls extensively in Test Projects. It looks strange to me to use Asserts statement in normal code (other than test projects).
Why -> Because i have never used it this way, never read in any book about it also.
Questions
1. Is it Ok to use Asserts for preconditions
2. Pros/Cons of Asserts over Checking the parameters and throwing Argument___Exception
If it matters, I am asking for .NET (not for java)
You might want to look into Code Contracts. They provide both static and runtime checking of your methods, and you can apply them to your interfaces as well, so that the contracts become part of your public API.
As an example, from copied from some of my own code (this code implements contracts on an interface):
using System;
using System.Diagnostics.Contracts;
using Project.Contracts.Model.Accounts;
using Project.Contracts.Services;
/// <summary>
/// Data access for accounts.
/// </summary>
[ContractClass(typeof(AccountRepositoryContract))]
public interface IAccountRepository
{
/// <summary>
/// Gets the user by id.
/// </summary>
/// <param name="userId">The user id.</param>
/// <returns>The user, or <c>null</c> if user not found.</returns>
[Pure]
User GetUserById(int userId);
}
/// <summary>
/// Contract class for <see cref="IAccountRepository"/>.
/// </summary>
[ContractClassFor(typeof(IAccountRepository))]
internal abstract class AccountRepositoryContract : IAccountRepository
{
/// <summary>
/// Gets the user by id.
/// </summary>
/// <param name="userId">The user id.</param>
/// <returns>
/// The user, or <c>null</c> if user not found.
/// </returns>
public User GetUserById(int userId)
{
Contract.Requires<ArgumentException>(userId > 0);
return null;
}
}
A simpler, yet more comprehensive, example:
public class Foo
{
public String GetStuff(IThing thing)
{
// Throws ArgumentNullException if thing == null
Contract.Requires<ArgumentNullException>(thing != null);
// Static checking that this method never returns null
Contract.Ensures(Contract.Result<String>() != null);
return thing.ToString();
}
}
This post is only about Microsoft.VisualStudio.TestTools.UnitTesting.Assert
, not Debug.Assert
.
I would not recommend that, since the Assert
class is in the Microsoft.VisualStudio.TestTools.UnitTesting
namespace, which is testing stuff rather than production tools. They're in a separate assembly too which you should not need to reference from non-testing code.
ArgumentException
(illegal argument, with ArgumentNullException
and ArgumentOutOfRangeException
for further splitting) and and InvalidOperationException
(illegal state) are there for condition checking.
As an alternative, there are code contracts too. See Steve's answer.
They are effectively two different Asserts. The Assert you use in unit tests is for triggering a test failure (and of course, they are always tested). The Asserts you use in other code are a separate function (System.Diagnostics.Debug.Assert()
), and are used as a helping tool during development, to alert you if expected conditions are not satisfied. However, these assertions are only tested in debug builds. If you make a release build, the assert will have no effect. So it is not a general error-handling tool, and you should not plan on it to catch errors.
It is simply to catch logic errors during testing and development, to tell you if your assumptions hold. And as such, yes, it is very useful for testing pre- and postconditions.
Note that this kind of Assert is a bit contentious, because it may become a crutch you end up using instead of proper error handling, and since it has no effect in release builds, you may end up releasing software with nonexistent error handling. (For example, don't use Assert to check that a file exists. It's a real error that can actually occur in the real world, so it needs real-world error handling.) But personally, I think it's a very useful tool, for testing pre- and postconditions without having to worry about the performance overhead (since the test gets removed in release builds, it is effectively free, and it triggers the debugger when the assertion fails, rather than just throwing an exception)
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