Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Catel - Part 4 of n: Unit testing with Catel

, 28 Jan 2011 CPOL
This article explains how to write unit tests for MVVM using Catel.
Catel-04_01-unittesting.zip
src
Catel.Articles.04 - Unit testing
Models
Properties
Settings.settings
Resources
Images
add.png
delete.png
edit.png
group.png
UI
Data
Converters
ViewModels
Windows
Catel.Articles.04 - Unit testing.Test
Models
Properties
UI
ViewModels
Catel.Articles.Base
Data
Attributes
Properties
Settings.settings
Resources
Images
CatenaLogic.png
Preview.png
Run.png
ShowCode.png
UI
Controls
Helpers
ViewModels
Windows
Catel.Core
Attributes
ClassDiagrams
DataObjectBase.cd
SavableDataObjectBase.cd
Collections
Helpers
ComponentModel
Data
Attributes
Exceptions
Interfaces
Diagnostics
Extensions
Helpers
Exceptions
Helpers
IO
Exceptions
IoC
LLBLGen
Log4net
Appender
Extensions
Helpers
MVVM
Commands
Interfaces
Exceptions
Services
EventArgs
Exceptions
Interfaces
ViewModels
Attributes
Interfaces
Properties
Reflection
Exceptions
Extensions
Helpers
Runtime
Serialization
Attributes
Helpers
Security
Cryptography
Helpers
Catel.Examples.Models
Properties
Catel.Examples.PersonApplication
Properties
Settings.settings
Resources
Images
add.png
delete.png
edit.png
group.png
UI
Data
Converters
ViewModels
Windows
Catel.Examples.Silverlight
Properties
Resources
Images
add.png
delete.png
edit.png
group.png
UI
Data
Converters
Pages
ViewModels
Windows
Catel.Examples.Silverlight.Web
Catel.Examples.Silverlight.Web.csproj.user
ClientBin
Properties
Catel.FxCop
Catel.Silverlight
Diagnostics
log4net
Core
MVVM
Commands
Services
ViewModels
Properties
Catel.Core
Catel.Windows
Reflection
Themes
Generic
Assets
Old
Windows
Controls
Data
Converters
Helpers
Helpers
Catel.Silverlight.Test
Properties
Catel.Silverlight.Test.Web
Catel.Silverlight.Test.Web.csproj.user
ClientBin
Properties
Catel.snk
Catel.Templates.WpfApplication
Properties
Settings.settings
UI
Controls
ViewModels
Windows
Catel.Templates.WpfItemTemplates
Properties
UI
Controls
ViewModels
Windows
Catel.Test
Collections
Convert
Data
Helpers
IO
MVVM
UI
ViewModels
Properties
Reflection
Runtime
Serialization
Security
Cryptography
Test References
Catel.Windows.accessor
Windows
Data
Converters
Catel.vsmdi
Catel.Windows
ClassDiagrams
ViewModelBase.cd
Collections
Extensions
Helpers
MVVM
Commands
Services
Test
UI
ViewModels
Properties
Settings.settings
Resources
Images
Add.png
ClearOutput.png
Edit.png
Error.png
Loading.gif
Preview.png
Remove.png
Save.png
TipOfTheDay.png
Warning.png
Themes
Aero
ExpressionDark
Assets
Generic
Assets
Controls
Jetpack
Assets
background.png
Old
SunnyOrange
Assets
Windows
Controls
Extensions
LinkLabel
StackGrid
Data
Converters
Helpers
Documents
Extensions
Extensions
Helpers
Input
Markup
Media
Effects
EmptyEffect
EmptyEffect.fx
EmptyEffect.ps
EmptyEffect.fx
GrayscaleEffect
GrayscaleEffect.fx
GrayscaleEffect.ps
Extensions
Imaging
Extensions
Windows
DataWindow
TipOfTheDay
Local.testsettings
Settings.StyleCop
TraceAndTestImpact.testsettings
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.Xml.Serialization;
using Catel.Data;

namespace Catel.Test.Data
{
	#region Test classes
	/// <summary>
	/// IniEntry Data object class which fully supports serialization, property changed notifications,
	/// backwards compatibility and error checking.
	/// </summary>
#if !SILVERLIGHT
	[Serializable]
#endif
	public class IniEntry : SavableDataObjectBase<IniEntry>
	{
		#region Variables
		#endregion

		#region Constructor & destructor
		/// <summary>
		/// Initializes a new object from scratch.
		/// </summary>
		public IniEntry() { }

#if !SILVERLIGHT
		/// <summary>
		/// Initializes a new object based on <see cref="SerializationInfo"/>.
		/// </summary>
		/// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
		/// <param name="context"><see cref="StreamingContext"/>.</param>
		protected IniEntry(SerializationInfo info, StreamingContext context)
			: base(info, context) { }
#endif
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the group.
		/// </summary>
		public string Group
		{
			get { return GetValue<string>(GroupProperty); }
			set { SetValue(GroupProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData GroupProperty = RegisterProperty("Group", typeof(string), string.Empty);

		/// <summary>
		/// Gets or sets the key.
		/// </summary>
		public string Key
		{
			get { return GetValue<string>(KeyProperty); }
			set { SetValue(KeyProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData KeyProperty = RegisterProperty("Key", typeof(string), string.Empty);

		/// <summary>
		/// Gets or sets the value.
		/// </summary>
		public string Value
		{
			get { return GetValue<string>(ValueProperty); }
			set { SetValue(ValueProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData ValueProperty = RegisterProperty("Value", typeof(string), string.Empty);
		#endregion

		#region Methods
        /// <summary>
        /// Sets whether this object is read-only or not.
        /// </summary>
        /// <param name="isReadOnly">if set to <c>true</c>, the object will become read-only.</param>
        public void SetReadOnly(bool isReadOnly)
        {
            IsReadOnly = isReadOnly;
        }

		/// <summary>
		/// Validates the fields.
		/// </summary>
		protected override void ValidateFields()
		{
			if (string.IsNullOrEmpty(Group)) SetFieldError(GroupProperty, "Group is mandatory");
			if (string.IsNullOrEmpty(Key)) SetFieldError(KeyProperty, "Key is mandatory");
			if (string.IsNullOrEmpty(Value)) SetFieldError(ValueProperty, "Value is mandatory");
		}
		#endregion
	}

	/// <summary>
	/// Extended class of the <see cref="IniEntry"/> class.
	/// </summary>
#if !SILVERLIGHT
	[Serializable]
#endif
	public class ExtendedIniEntry : IniEntry
	{
		#region Enums
		/// <summary>
		/// Enum to test the comparison of enums when registering the same property multiple times.
		/// </summary>
		public enum IniEntryType
		{
			/// <summary>
			/// New ini type.
			/// </summary>
			New,

			/// <summary>
			/// Old ini type.
			/// </summary>
			Old
		}
		#endregion

		#region Constructor & destructor
		/// <summary>
		/// Initializes a new object from scratch.
		/// </summary>
		public ExtendedIniEntry() { }

#if !SILVERLIGHT
		/// <summary>
		/// Initializes a new object based on <see cref="SerializationInfo"/>.
		/// </summary>
		/// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
		/// <param name="context"><see cref="StreamingContext"/>.</param>
		protected ExtendedIniEntry(SerializationInfo info, StreamingContext context)
			: base(info, context) { }
#endif
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the default value.
		/// </summary>
		public string DefaultValue
		{
			get { return GetValue<string>(DefaultValueProperty); }
			set { SetValue(DefaultValueProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData DefaultValueProperty = RegisterProperty("DefaultValue", typeof(string), string.Empty);

		/// <summary>
		/// Gets or sets the property value.
		/// </summary>
		public IniEntryType Type
		{
			get { return GetValue<IniEntryType>(TypeProperty); }
			set { SetValue(TypeProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData TypeProperty = RegisterProperty("Type", typeof(IniEntryType), IniEntryType.Old);
		#endregion
	}

	/// <summary>
	/// IniFile Data object class which fully supports serialization, property changed notifications,
	/// backwards compatibility and error checking.
	/// </summary>
#if !SILVERLIGHT
	[Serializable]
#endif
	public class IniFile : SavableDataObjectBase<IniFile>
	{
		#region Variables
		#endregion

		#region Constructor & destructor
		/// <summary>
		/// Initializes a new object from scratch.
		/// </summary>
		public IniFile() { }

#if !SILVERLIGHT
		/// <summary>
		/// Initializes a new object based on <see cref="SerializationInfo"/>.
		/// </summary>
		/// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
		/// <param name="context"><see cref="StreamingContext"/>.</param>
		protected IniFile(SerializationInfo info, StreamingContext context)
			: base(info, context) { }
#endif
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the filename.
		/// </summary>
		public string FileName
		{
			get { return GetValue<string>(FileNameProperty); }
			set { SetValue(FileNameProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData FileNameProperty = RegisterProperty("FileName", typeof(string), string.Empty);

		/// <summary>
		/// Gets or sets the collection of ini entries..
		/// </summary>
		public ObservableCollection<IniEntry> IniEntryCollection
		{
			get { return GetValue<ObservableCollection<IniEntry>>(IniEntryCollectionProperty); }
			set { SetValue(IniEntryCollectionProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData IniEntryCollectionProperty = RegisterProperty("IniEntryCollection", typeof(ObservableCollection<IniEntry>), new ObservableCollection<IniEntry>());
		#endregion

		#region Methods
		/// <summary>
		/// Validates the fields.
		/// </summary>
		protected override void ValidateFields()
		{
			if (string.IsNullOrEmpty(FileName)) SetFieldError(FileNameProperty, "File name is mandatory");
		}
		#endregion
	}

	/// <summary>
	/// ComputerSettings Data object class which fully supports serialization, property changed notifications,
	/// backwards compatibility and error checking.
	/// </summary>
#if !SILVERLIGHT
	[Serializable]
#endif
	public class ComputerSettings : SavableDataObjectBase<ComputerSettings>
	{
		#region Constants
		private static readonly ObservableCollection<IniFile> DefaultIniFileCollection = InitializeDefaultIniFileCollection();
		#endregion

		#region Variables
		#endregion

		#region Constructor & destructor
		/// <summary>
		/// Initializes a new object from scratch.
		/// </summary>
		public ComputerSettings() { }

#if !SILVERLIGHT
		/// <summary>
		/// Initializes a new object based on <see cref="SerializationInfo"/>.
		/// </summary>
		/// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
		/// <param name="context"><see cref="StreamingContext"/>.</param>
		protected ComputerSettings(SerializationInfo info, StreamingContext context)
			: base(info, context) { }
#endif
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the computer name.
		/// </summary>
		public string ComputerName
		{
			get { return GetValue<string>(ComputerNameProperty); }
			set { SetValue(ComputerNameProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData ComputerNameProperty = RegisterProperty("ComputerName", typeof(string), string.Empty);

		/// <summary>
		/// Gets or sets the collection of ini files.
		/// </summary>
		public ObservableCollection<IniFile> IniFileCollection
		{
			get { return GetValue<ObservableCollection<IniFile>>(IniFileCollectionProperty); }
			set { SetValue(IniFileCollectionProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData IniFileCollectionProperty = RegisterProperty("IniFileCollection", typeof(ObservableCollection<IniFile>), DefaultIniFileCollection);
		#endregion

		#region Methods
		/// <summary>
		/// Initializes the default ini file collection.
		/// </summary>
		/// <returns>New <see cref="ObservableCollection{T}"/>.</returns>
		private static ObservableCollection<IniFile> InitializeDefaultIniFileCollection()
		{
			// Create default ini files
			var result = new ObservableCollection<IniFile>();

			// Add 3 files
			result.Add(DataObjectBaseTestHelper.CreateIniFileObject("Initial file 1", new[] { DataObjectBaseTestHelper.CreateIniEntryObject("G1", "K1", "V1") }));
			result.Add(DataObjectBaseTestHelper.CreateIniFileObject("Initial file 2", new[] { DataObjectBaseTestHelper.CreateIniEntryObject("G2", "K2", "V2") }));
			result.Add(DataObjectBaseTestHelper.CreateIniFileObject("Initial file 3", new[] { DataObjectBaseTestHelper.CreateIniEntryObject("G3", "K3", "V3") }));

			// Return result
			return result;
		}
		#endregion
	}

	/// <summary>
	/// ComputerSettingsWithXmlMappings Data object class which fully supports serialization, property changed notifications,
	/// backwards compatibility and error checking.
	/// </summary>
#if !SILVERLIGHT
	[Serializable]
#endif
	public class ComputerSettingsWithXmlMappings : SavableDataObjectBase<ComputerSettingsWithXmlMappings>
	{
		#region Variables
		#endregion

		#region Constructor & destructor
		/// <summary>
		/// Initializes a new object from scratch.
		/// </summary>
		public ComputerSettingsWithXmlMappings() { }

#if !SILVERLIGHT
		/// <summary>
		/// Initializes a new object based on <see cref="SerializationInfo"/>.
		/// </summary>
		/// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
		/// <param name="context"><see cref="StreamingContext"/>.</param>
		protected ComputerSettingsWithXmlMappings(SerializationInfo info, StreamingContext context)
			: base(info, context) { }
#endif
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the computer name.
		/// </summary>
		[XmlElement("MappedComputerName")]
		public string ComputerName
		{
			get { return GetValue<string>(ComputerNameProperty); }
			set { SetValue(ComputerNameProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData ComputerNameProperty = RegisterProperty("ComputerName", typeof(string), string.Empty);

		/// <summary>
		/// Gets or sets the collection of ini files.
		/// </summary>
		[XmlElement("IniFiles")]
		public ObservableCollection<IniFile> IniFileCollection
		{
			get { return GetValue<ObservableCollection<IniFile>>(IniFileCollectionProperty); }
			set { SetValue(IniFileCollectionProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData IniFileCollectionProperty = RegisterProperty("IniFileCollection", typeof(ObservableCollection<IniFile>), new ObservableCollection<IniFile>());
		#endregion
	}

    #region Enums
    public enum Gender
    {
        Male,

        Female
    }
    #endregion

    /// <summary>
    /// ObjectWithCustomType Data object class which fully supports serialization, property changed notifications,
    /// backwards compatibility and error checking.
    /// </summary>
#if !SILVERLIGHT
[Serializable]
#endif
    public class ObjectWithCustomType : SavableDataObjectBase<ObjectWithCustomType>
    {
        #region Variables
        #endregion

        #region Constructor & destructor
        /// <summary>
        /// Initializes a new object from scratch.
        /// </summary>
        public ObjectWithCustomType() { }

#if !SILVERLIGHT	
    /// <summary>
    /// Initializes a new object based on <see cref="SerializationInfo"/>.
    /// </summary>
    /// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
    /// <param name="context"><see cref="StreamingContext"/>.</param>
    protected ObjectWithCustomType(SerializationInfo info, StreamingContext context)
        : base(info, context) { }
#endif
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the first name.
        /// </summary>
        public string FirstName
        {
            get { return GetValue<string>(FirstNameProperty); }
            set { SetValue(FirstNameProperty, value); }
        }

        /// <summary>
        /// Register the FirstName property so it is known in the class.
        /// </summary>
        public static readonly PropertyData FirstNameProperty = RegisterProperty("FirstName", typeof(string), string.Empty);

        /// <summary>
        /// Gets or sets the gender.
        /// </summary>
        public Gender Gender
        {
            get { return GetValue<Gender>(GenderProperty); }
            set { SetValue(GenderProperty, value); }
        }

        /// <summary>
        /// Register the Gender property so it is known in the class.
        /// </summary>
        public static readonly PropertyData GenderProperty = RegisterProperty("Gender", typeof(Gender), Gender.Male);
        #endregion

        #region Methods
        #endregion
    }

    /// <summary>
    /// ObjectWithXmlMappings Data object class which fully supports serialization, property changed notifications,
    /// backwards compatibility and error checking.
    /// </summary>
#if !SILVERLIGHT
    [Serializable]
#endif
    public class ObjectWithXmlMappings : DataObjectBase<ObjectWithXmlMappings>
    {
        #region Variables
        #endregion

        #region Constructor & destructor
        /// <summary>
        /// Initializes a new object from scratch.
        /// </summary>
        public ObjectWithXmlMappings() { }

#if !SILVERLIGHT
        /// <summary>
        /// Initializes a new object based on <see cref="SerializationInfo"/>.
        /// </summary>
        /// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
        /// <param name="context"><see cref="StreamingContext"/>.</param>
        protected ObjectWithXmlMappings(SerializationInfo info, StreamingContext context)
            : base(info, context) { }
#endif
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the property without an xml mapping.
        /// </summary>
        public string PropertyWithoutMapping
        {
            get { return GetValue<string>(PropertyWithoutMappingProperty); }
            set { SetValue(PropertyWithoutMappingProperty, value); }
        }

        /// <summary>
        /// Register the PropertyWithoutMapping property so it is known in the class.
        /// </summary>
        public static readonly PropertyData PropertyWithoutMappingProperty = RegisterProperty("PropertyWithoutMapping", typeof(string), "withoutMapping");

        /// <summary>
        /// Gets or sets the property with an xml mapping.
        /// </summary>
        [XmlElement("MappedXmlProperty")]
        public string PropertyWithMapping
        {
            get { return GetValue<string>(PropertyWithMappingProperty); }
            set { SetValue(PropertyWithMappingProperty, value); }
        }

        /// <summary>
        /// Register the PropertyWithMapping property so it is known in the class.
        /// </summary>
        public static readonly PropertyData PropertyWithMappingProperty = RegisterProperty("PropertyWithMapping", typeof(string), "withMapping");
        #endregion
    }

	/// <summary>
	/// ObjectWithPrivateMembers Data object class which fully supports serialization, property changed notifications,
	/// backwards compatibility and error checking.
	/// </summary>
#if !SILVERLIGHT
	[Serializable]
#endif
	public class ObjectWithPrivateMembers : SavableDataObjectBase<ObjectWithPrivateMembers>
	{
		#region Variables
		#endregion

		#region Constructor & destructor
		/// <summary>
		/// Initializes a new object from scratch.
		/// </summary>
		public ObjectWithPrivateMembers() { }

		/// <summary>
		/// Initializes a new object from scratch.
		/// </summary>
		public ObjectWithPrivateMembers(string privateMemberValue)
		{
			// Store values
			PrivateMember = privateMemberValue;
		}

#if !SILVERLIGHT
		/// <summary>
		/// Initializes a new object based on <see cref="SerializationInfo"/>.
		/// </summary>
		/// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
		/// <param name="context"><see cref="StreamingContext"/>.</param>
		protected ObjectWithPrivateMembers(SerializationInfo info, StreamingContext context)
			: base(info, context) { }
#endif
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the public member.
		/// </summary>
		public string PublicMember
		{
			get { return GetValue<string>(PublicMemberProperty); }
			set { SetValue(PublicMemberProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData PublicMemberProperty = RegisterProperty("PublicMember", typeof(string), "Public member");

		/// <summary>
		/// Gets or sets the private member.
		/// </summary>
		private string PrivateMember
		{
			get { return GetValue<string>(PrivateMemberProperty); }
			set { SetValue(PrivateMemberProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		private static readonly PropertyData PrivateMemberProperty = RegisterProperty("PrivateMember", typeof(string), "Private member");
		#endregion
	}

	/// <summary>
	/// ObjectWithPrivateConstructor Data object class which fully supports serialization, property changed notifications,
	/// backwards compatibility and error checking.
	/// </summary>
#if !SILVERLIGHT
	[Serializable]
#endif
	public class ObjectWithPrivateConstructor : SavableDataObjectBase<ObjectWithPrivateConstructor>
	{
		#region Constructor & destructor
		/// <summary>
		/// Initializes a new object from scratch.
		/// </summary>
		protected ObjectWithPrivateConstructor() { }

		/// <summary>
		/// Initializes a new instance of the <see cref="ObjectWithPrivateConstructor"/> class.
		/// </summary>
		/// <param name="myValue">My value.</param>
		public ObjectWithPrivateConstructor(string myValue)
		{
			// Store values
			MyValue = myValue;
		}

#if !SILVERLIGHT
		/// <summary>
		/// Initializes a new object based on <see cref="SerializationInfo"/>.
		/// </summary>
		/// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
		/// <param name="context"><see cref="StreamingContext"/>.</param>
		protected ObjectWithPrivateConstructor(SerializationInfo info, StreamingContext context)
			: base(info, context) { }
#endif
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets my value.
		/// </summary>
		public string MyValue
		{
			get { return GetValue<string>(MyValueProperty); }
			set { SetValue(MyValueProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData MyValueProperty = RegisterProperty("MyValue", typeof(string), string.Empty);
		#endregion
	}

	/// <summary>
	/// Parent Data object class which fully supports serialization, property changed notifications,
	/// backwards compatibility and error checking.
	/// </summary>
#if !SILVERLIGHT
	[Serializable]
#endif
	public class Parent : SavableDataObjectBase<Parent>
	{
		#region Constructor & destructor
		/// <summary>
		/// Initializes a new object from scratch.
		/// </summary>
#if SILVERLIGHT
        public
#else
        private
#endif		
        Parent() { }

		/// <summary>
		/// Initializes a new object from scratch.
		/// </summary>
		public Parent(string name)
		{
			// Store values
			Name = name;
		}

#if !SILVERLIGHT
		/// <summary>
		/// Initializes a new object based on <see cref="SerializationInfo"/>.
		/// </summary>
		/// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
		/// <param name="context"><see cref="StreamingContext"/>.</param>
		protected Parent(SerializationInfo info, StreamingContext context)
			: base(info, context) { }
#endif
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the name of the parent.
		/// </summary>
		public string Name
		{
			get { return GetValue<string>(NameProperty); }
			set { SetValue(NameProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData NameProperty = RegisterProperty("Name", typeof(string), string.Empty);

		/// <summary>
		/// Gets or sets the child collection.
		/// </summary>
		public Collection<Child> Children
		{
			get { return GetValue<Collection<Child>>(ChildrenProperty); }
			set { SetValue(ChildrenProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData ChildrenProperty = RegisterProperty("Children", typeof(Collection<Child>), new Collection<Child>(), true);
		#endregion

		#region Methods
		/// <summary>
		/// Creates a new child object.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <returns>New created child.</returns>
		public Child CreateChild(string name)
		{
			Child child = new Child(this, name);
			Children.Add(child);
			return child;
		}
		#endregion
	}

	/// <summary>
	/// Child Data object class which fully supports serialization, property changed notifications,
	/// backwards compatibility and error checking.
	/// </summary>
#if !SILVERLIGHT
	[Serializable]
#endif
	public class Child : SavableDataObjectBase<Child>
	{
		#region Constructor & destructor
		/// <summary>
		/// Initializes a new object from scratch.
		/// </summary>
#if SILVERLIGHT
        public 
#else
        protected
#endif
		Child() { }

		/// <summary>
		/// Initializes a new instance of the <see cref="Child"/> class.
		/// </summary>
		/// <param name="parent">The parent.</param>
		/// <param name="name">The name.</param>
		public Child(Parent parent, string name)
		{
			// Set parent
			SetParent(parent);

			// Store values
			Name = name;
		}

#if !SILVERLIGHT
		/// <summary>
		/// Initializes a new object based on <see cref="SerializationInfo"/>.
		/// </summary>
		/// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
		/// <param name="context"><see cref="StreamingContext"/>.</param>
		protected Child(SerializationInfo info, StreamingContext context)
			: base(info, context) { }
#endif
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the name of the child.
		/// </summary>
		public string Name
		{
			get { return GetValue<string>(NameProperty); }
			set { SetValue(NameProperty, value); }
		}

		/// <summary>
		/// Register the property so it is known in the class.
		/// </summary>
		public static readonly PropertyData NameProperty = RegisterProperty("Name", typeof(string), string.Empty);
		#endregion
	}

	/// <summary>
	/// object without default values containing both a reference and value type property.
	/// </summary>
	public class ObjectWithoutDefaultValues : DataObjectBase<ObjectWithoutDefaultValues>
	{
		/// <summary>
		/// Gets or sets a value type.
		/// </summary>
		public int ValueType
		{
			get { return GetValue<int>(ValueTypeProperty); }
			set { SetValue(ValueTypeProperty, value); }
		}

		/// <summary>
		/// Register the ValueType property so it is known in the class.
		/// </summary>
		public static readonly PropertyData ValueTypeProperty = RegisterProperty("ValueType", typeof(int), 1);

		/// <summary>
		/// Gets or sets a value type without default value.
		/// </summary>
		public int ValueTypeWithoutDefaultValue
		{
			get { return GetValue<int>(ValueTypeWithoutDefaultValueProperty); }
			set { SetValue(ValueTypeWithoutDefaultValueProperty, value); }
		}

		/// <summary>
		/// Register the ValueTypeWithoutDefaultValue property so it is known in the class.
		/// </summary>
		public static readonly PropertyData ValueTypeWithoutDefaultValueProperty = RegisterProperty("ValueTypeWithoutDefaultValue", typeof(int));

		/// <summary>
		/// Gets or sets a reference type.
		/// </summary>
		public object ReferenceType
		{
			get { return GetValue<object>(ReferenceTypeProperty); }
			set { SetValue(ReferenceTypeProperty, value); }
		}

		/// <summary>
		/// Register the ReferenceType property so it is known in the class.
		/// </summary>
		public static readonly PropertyData ReferenceTypeProperty = RegisterProperty("ReferenceType", typeof(object), new object());

		/// <summary>
		/// Gets or sets a reference type without default value.
		/// </summary>
		public object ReferenceTypeWithoutDefaultValue
		{
			get { return GetValue<object>(ReferenceTypeWithoutDefaultValueProperty); }
			set { SetValue(ReferenceTypeWithoutDefaultValueProperty, value); }
		}

		/// <summary>
		/// Register the ReferenceTypeWithoutDefaultValue property so it is known in the class.
		/// </summary>
		public static readonly PropertyData ReferenceTypeWithoutDefaultValueProperty = RegisterProperty("ReferenceTypeWithoutDefaultValue", typeof(object));
	}

	/// <summary>
	/// object with non-serializable members.
	/// </summary>
	public class ObjectWithNonSerializableMembers : DataObjectBase<ObjectWithNonSerializableMembers>
	{
		/// <summary>
		/// Gets or sets a non-serializable value.
		/// </summary>
		public IEnumerable<string> NonSerializableValue
		{
			get { return GetValue<IEnumerable<string>>(NonSerializableValueProperty); }
			set { SetValue(NonSerializableValueProperty, value); }
		}

		/// <summary>
		/// Register the NonSerializableValue property so it is known in the class.
		/// </summary>
		public static readonly PropertyData NonSerializableValueProperty = RegisterProperty("NonSerializableValue", typeof(IEnumerable<string>), new string[] { "a", "b", "c" });
	}

	/// <summary>
	/// object with non-serializable members decorated with the <see cref="AllowNonSerializableMembersAttribute"/>.
	/// </summary>
	[AllowNonSerializableMembers]
	public class ObjectWithNonSerializableMembersDecoratedWithAllowNonSerializableMembersAttribute : DataObjectBase<ObjectWithNonSerializableMembersDecoratedWithAllowNonSerializableMembersAttribute>
	{
		/// <summary>
		/// Gets or sets a non-serializable value.
		/// </summary>
		public IEnumerable<string> NonSerializableValue
		{
			get { return GetValue<IEnumerable<string>>(NonSerializableValueProperty); }
			set { SetValue(NonSerializableValueProperty, value); }
		}

		/// <summary>
		/// Register the NonSerializableValue property so it is known in the class.
		/// </summary>
		public static readonly PropertyData NonSerializableValueProperty = RegisterProperty("NonSerializableValue", typeof(IEnumerable<string>), new string[] { "a", "b", "c" });
	}

    /// <summary>
    /// ObjectWithValidation Data object class which fully supports serialization, property changed notifications,
    /// backwards compatibility and error checking.
    /// </summary>
#if !SILVERLIGHT
    [Serializable]
#endif
    public class ObjectWithValidation : DataObjectBase<ObjectWithValidation>
    {
        #region Constants
        public const string ValueThatHasNoWarningsOrErrors = "NoWarningsOrErrors";
        public const string ValueThatCausesFieldWarning = "FieldWarning";
        public const string ValueThatCausesBusinessWarning = "BusinessWarning";
        public const string ValueThatCausesFieldError = "FieldError";
        public const string ValueThatCausesBusinessError = "BusinessError";
        #endregion

        #region Variables
        #endregion

        #region Constructor & destructor
        /// <summary>
        /// Initializes a new object from scratch.
        /// </summary>
        public ObjectWithValidation() { }

#if !SILVERLIGHT
        /// <summary>
        /// Initializes a new object based on <see cref="SerializationInfo"/>.
        /// </summary>
        /// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
        /// <param name="context"><see cref="StreamingContext"/>.</param>
        protected ObjectWithValidation(SerializationInfo info, StreamingContext context)
            : base(info, context) { }
#endif
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the value to validate.
        /// </summary>
        public string ValueToValidate
        {
            get { return GetValue<string>(ValueToValidateProperty); }
            set { SetValue(ValueToValidateProperty, value); }
        }

        /// <summary>
        /// Register the ValueToValidate property so it is known in the class.
        /// </summary>
        public static readonly PropertyData ValueToValidateProperty = RegisterProperty("ValueToValidate", typeof(string), ValueThatHasNoWarningsOrErrors);
        #endregion

        #region Methods
        /// <summary>
        /// Validates the fields.
        /// </summary>
        protected override void ValidateFields()
        {
            if (ValueToValidate == ValueThatCausesFieldWarning) SetFieldWarning(ValueToValidateProperty, "Field warning");
            if (ValueToValidate == ValueThatCausesFieldError) SetFieldError(ValueToValidateProperty, "Field error");
        }

        /// <summary>
        /// Validates the business rules.
        /// </summary>
        protected override void ValidateBusinessRules()
        {
            if (ValueToValidate == ValueThatCausesBusinessWarning) SetBusinessRuleWarning("Business rule warning");
            if (ValueToValidate == ValueThatCausesBusinessError) SetBusinessRuleError("Business rule error");
        }
        #endregion
    }
	#endregion

	/// <summary>
	/// <see cref="DataObjectBase"/> test helper class.
	/// </summary>
	public abstract class DataObjectBaseTestHelper
	{
		#region Helper methods
		/// <summary>
		/// Creates the ini entry object.
		/// </summary>
		/// <param name="group">The group.</param>
		/// <param name="key">The key.</param>
		/// <param name="value">The value.</param>
		/// <returns>New <see cref="IniEntry"/>.</returns>
		public static IniEntry CreateIniEntryObject(string group, string key, string value)
		{
			return new IniEntry
					   {
						   Group = group,
						   Key = key,
						   Value = value
					   };
		}

		/// <summary>
		/// Creates the ini entry object.
		/// </summary>
		/// <returns>New <see cref="IniEntry"/>.</returns>
		public static IniEntry CreateIniEntryObject()
		{
			return CreateIniEntryObject("MyGroup", "MyKey", "MyValue");
		}

		/// <summary>
		/// Creates the ini file object.
		/// </summary>
		/// <param name="fileName">Name of the file.</param>
		/// <param name="iniEntries">The ini entries.</param>
		/// <returns>New <see cref="IniFile"/>.</returns>
		public static IniFile CreateIniFileObject(string fileName, IEnumerable<IniEntry> iniEntries)
		{
			// Ini file
			IniFile iniFile = new IniFile
								  {
									  FileName = fileName
								  };

			// Add entries
			foreach (IniEntry iniEntry in iniEntries)
			{
				iniFile.IniEntryCollection.Add(iniEntry);
			}

			// Return result
			return iniFile;
		}

		/// <summary>
		/// Creates the ini file object with some predefined values.
		/// </summary>
		/// <returns>New <see cref="IniFile"/>.</returns>
		public static IniFile CreateIniFileObject()
		{
			// Declare variables
			List<IniEntry> iniEntries = new List<IniEntry>();

			// Create collection
			for (int i = 0; i < 3; i++)
			{
				iniEntries.Add(CreateIniEntryObject(string.Format("Group {0}", i),
					string.Format("Group {0}", i),
					string.Format("Value {0}", i)));
			}

			// Create object
			return CreateIniFileObject("MyIniFile", iniEntries);
		}

		/// <summary>
		/// Creates the computer settings object.
		/// </summary>
		/// <param name="computerName">Name of the computer.</param>
		/// <param name="iniFiles">The ini files.</param>
		/// <returns>New <see cref="ComputerSettings"/>.</returns>
		public static ComputerSettings CreateComputerSettingsObject(string computerName, IEnumerable<IniFile> iniFiles)
		{
			// Computer settings
			ComputerSettings computerSettings = new ComputerSettings
													{
														ComputerName = computerName
													};

			// Add entries
			foreach (IniFile iniFile in iniFiles)
			{
				computerSettings.IniFileCollection.Add(iniFile);
			}

			// Return result
			return computerSettings;
		}

		/// <summary>
		/// Creates the computer settings object with some predefined values.
		/// </summary>
		/// <returns>New <see cref="IniFile"/>.</returns>
		public static ComputerSettings CreateComputerSettingsObject()
		{
			// Declare variables
			List<IniFile> iniFiles = new List<IniFile>();

			// Create collection
			for (int i = 0; i < 3; i++)
			{
				// Create object
				IniFile iniFile = CreateIniFileObject();
				iniFile.FileName = string.Format("MyFile {0}", i);
				iniFiles.Add(iniFile);
			}

			// Create object
			return CreateComputerSettingsObject("MyComputer", iniFiles);
		}

		/// <summary>
		/// Creates the computer settings object with xml mappings.
		/// </summary>
		/// <param name="computerName">Name of the computer.</param>
		/// <param name="iniFiles">The ini files.</param>
		/// <returns>New <see cref="ComputerSettings"/>.</returns>
		public static ComputerSettingsWithXmlMappings CreateComputerSettingsWithXmlMappingsObject(string computerName, IEnumerable<IniFile> iniFiles)
		{
			// Copy and return
			return CreateComputerSettingsCopy(CreateComputerSettingsObject(computerName, iniFiles));
		}

		/// <summary>
		/// Creates the computer settings with xml mappings object with some predefined values.
		/// </summary>
		/// <returns>New <see cref="IniFile"/>.</returns>
		public static ComputerSettingsWithXmlMappings CreateComputerSettingsWithXmlMappingsObject()
		{
			// Copy and return
			return CreateComputerSettingsCopy(CreateComputerSettingsObject());
		}

		/// <summary>
		/// Creates the computer settings copy.
		/// </summary>
		/// <param name="computerSettings">The computer settings.</param>
		/// <returns></returns>
		public static ComputerSettingsWithXmlMappings CreateComputerSettingsCopy(ComputerSettings computerSettings)
		{
			// Copy the properties
			ComputerSettingsWithXmlMappings computerSettingsWithXmlMappings = new ComputerSettingsWithXmlMappings();
			computerSettingsWithXmlMappings.ComputerName = computerSettings.ComputerName;
			computerSettingsWithXmlMappings.IniFileCollection = computerSettings.IniFileCollection;

			// Return result
			return computerSettingsWithXmlMappings;
		}
		#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Geert van Horrik
Software Developer CatenaLogic
Netherlands Netherlands
I am Geert van Horrik, and I have studied Computer Science in the Netherlands.
 
I love to write software using .NET (especially the combination of WPF and C#). I am also the lead developer of Catel, an open-source application development framework for WPF, Silverlight, WP7 and WinRT with the focus on MVVM.
 
I have my own company since January 1st 2007, called CatenaLogic. This company develops commercial and non-commercial software.
 
To download (or buy) applications I have written, visit my website: http://www.catenalogic.com
Follow on   Twitter

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141223.1 | Last Updated 28 Jan 2011
Article Copyright 2011 by Geert van Horrik
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid