Business rules and unit testing
Jul
16
WRITTEN BY:
16/07/2010 9:24 AM
When migrating code from CSLA 3.0x to 3.8.x and upgrading from private member variables to CSLA PropertyInfo backing we discovered a very important lesson from our unit tests. Business rules, unit tests and RegisterProperty configuration all need to be in sync.
PropertyInfo code generated by CodeSmith CSLA templates r1814
Those familiar with the CSLA RegisterProperty method will note that no
default value passed in, so it's going to default to
Nothing in VB.
Private Shared ReadOnly _fullNameProperty As PropertyInfo(Of System.String) = RegisterProperty(Of System.String)(Function(p As User) p.FullName, String.Empty)
Public Property FullName() As System.String
Get
Return GetProperty(_fullNameProperty)
End Get
Set (ByVal value As System.String)
SetProperty(_fullNameProperty, value)
End Set
End Property
Is Unique CSLA Business Rule Example
It is common to have database fields with unique text at businesses (E.g. Application User name), so you have to have a matching CSLA Business Rule. You will notice that the code has had to be upgraded to include a IsNothing check for it to pass Nunit tests when migrating from Member Field backing in the CSLAContrib generated 3.0x CSLA to the CodeSmith CSLA 3.8.x code.
'''
''' Uses a generic Exists(criteria) method to determine if a database column(s) are unique before the record gets saved to the database.
''' This works in combination with database unique constraints.
'''
'''
''' We check for IsDirty or IsNew to ensure we are not running this IsUnique check when we use the DataPortal_Fetch to get the information from the database. The database should manage constraints, so we should duplicate that effort.
''' TODO: Should look at making this a generic solution vs copying this to every business object.
'''
Private Shared Function IsUnique(Of T As BSO)(ByVal target As T, ByVal e As RuleArgs) As Boolean
Dim result As Boolean
If target.IsDirty OrElse target.IsNew Then
' Assumption: Field must be entered.
' IsNothing check inserted for CodeSmith CSLA templates, because the PropertyRegistration doesn't set a values, so it defaults to nothing or will cause Nunit tests to fail.
If Not IsNothing(target.FullName) AndAlso target.FullName.Trim.Length > 0 Then
Dim criteria As BSOCriteria = New UserCriteria
With criteria
.FullName = target.FullName
.IsUniqueExcludeIdentity = target.Identification
End With
' Use the codesmith Exists method to check for existing values.
If User.Exists(criteria) Then
' TODO: Waiting for the CodeSmith CSLA Templates to integrate PropertyInfo friendly names.
e.Description = String.Format("{0} value of '{1}' already exists and cannot be used.", "User", target.FullName)
result = False
Else
result = True
End If
Else
' Full name hasn't been entered, so it will be unique.
result = True
End If
Else
' Assumption: the database can enforce unique columns ;)
result = True
End If
Return result
End Function
Nunit code example.
Here is the simple unit test that found the issue. It looks fairly pointless, but in the end ensured I checked all the business rules migrated to the CodeSmith CSLA codebase.
Nunit Support
'''
''' Ensure Full Name is unique
'''
'''
Sub UniqueName()
Dim test As User
test = User.NewUser
With test
' We "know" that this name exists as we added it to the database for unit testing.
.FullName = ""
End With
' Should be a single broken rule
Assert.AreEqual(1, test.BrokenRulesCollection.Count, "Name field must be unique")
End Sub
Conclusion
It is amazing what a simple unit test can teach you about your code and the assumptions that have been made for you from a code generator. It should remind developers of the importance of a unit tests role when designing CSLA Business Rules and ensuring that they are correct before your code gets released. If you want to benefit from CodeSmiths CSLA templates, remember that simple unit tests are a valuable way to finding implicit assumptions.
COPYRIGHT ©2010 Jenasys Design Pty Ltd