如何获得编译时合同警告/错误

时间:2015-03-08 18:24:15

标签: c# code-contracts

我是合同的新手,我从概述中了解到它可以帮助您在编译时发现违反合同的行为。

当我的代码明确违反合同时,我没有收到编译时警告或错误。

我希望测试中设置Person.Name = null的代码行会给我一个警告或错误,因为它违反了合同。

如何调整代码以获取编译时消息?

注意:为了澄清,我将其置于单元测试中的唯一原因是获取编译时消息。测试本身目前通过,这是一个运行时方面;我想它应该通过,因为它是一个编译时测试而不是运行时测试。无论如何,问题是关于编译时消息或缺少编译时消息,而不是关于单元测试结果。

受测试代码:

using System;
using System.Diagnostics.Contracts;

namespace DomainModel
{
    [ContractClass(typeof(IPersonContract))]
    public interface IPerson
    {
        string Name { get; set; }
    }

    [ContractClassFor(typeof(IPerson))]
    public abstract class IPersonContract : IPerson
    {
        private IPersonContract() { }

        string IPerson.Name
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                Contract.Ensures(!string.IsNullOrEmpty(value));
            }
        }
    }

}

这是我的测试:

using Moq;
using NUnit.Framework;
using DomainModel;

namespace Unit
{
    /// <summary>
    /// A test class for IPerson
    /// </summary>
    [TestFixture()]
    public class IPersonShould
    {

        #region "Unit Tests"

        [Test()]
        public void ThrowWhenIPersonIsGivenEmptyName()
        {
            //set up
            IPerson IPerson = this.Person;
            string expectedResult = null;
            //Dim NameParam1 as String = Nothing
            Person.Name = null; // Would expect this line to generate warning or error
            //perform test
            string actualResult = IPerson.Name;

            //compare results
            Assert.AreEqual(expectedResult, actualResult);

        }
        #endregion

        #region "Setup and Tear down"

        private class MyPerson : IPerson {

            private string name;
            public string Name
            {
                get
                {
                    return name;
                }
                set
                {
                    name = value;
                }
            }
        }

        private MyPerson Person;

        /// <summary>
        /// This runs only once at the beginning of all tests and is used for all tests in the
        /// class.
        /// </summary>
        [TestFixtureSetUp()]
        public void InitialSetup()
        {
            Person = new MyPerson();
        }

        /// <summary>
        /// This runs only once at the end of all tests and is used for all tests in the class.
        /// </summary>
        [TestFixtureTearDown()]
        public void FinalTearDown()
        {
        }

        /// <summary>
        /// This setup function runs before each test method
        /// </summary>
        [SetUp()]
        public void SetupForEachTest()
        {

        }

        /// <summary>
        /// This setup function runs after each test method
        /// </summary>
        [TearDown()]
        public void TearDownForEachTest()
        {

        }

        #endregion

    }

}

以下是我目前的设置: enter image description here

1 个答案:

答案 0 :(得分:0)

我认为您对Code Contracts如何帮助您和其他开发人员感到有些困惑,所以让我试着帮助。

代码合同有两种方法可以提供帮助:

  1. 使用合同注释您的课程,为第三方开发人员提供参考您的库的人员,他们也使用代码合同来了解他们是否正确使用您的库。
    • 这是因为在运行时抛出异常,至少是Debug构建。异常的类型取决于您使用的工具合同的类型。
  2. 对于您团队中的开发人员,上述数字1也是如此。此外,代码合同可以为您的代码提供团队静态分析
    • 静态分析是编译启用了静态分析的项目后出现的警告和信息/事件项。
  3. 如您所知,您可以启用代码约定来执行静态分析(即&#34;编译时&#34;)和每个项目的运行时合同检查。

    您似乎已在 DomainModel 项目上启用了执行运行时合同检查执行静态合同检查执行静态合同检查将允许编译器在执行构建后通知您和您的团队合同的潜在问题。

    但真正的问题是,您已在单元测试项目中定义了Person。您是否在单元测试项目中启用 执行静态合同检查?如果没有,因为那里定义了Person,除非你启用它,否则不会对单元测试项目进行静态分析。

    此外,由于您在单元测试项目中定义Person,因此您还需要为单元测试启用 执行运行时合同检查以进行调试构建项目也是。这是不可取的,因为它会导致单元测试花费更长的时间来编译。我知道你打算最终移动实现,因为你只是试图理解你迄今为止编写的代码。

    但是,顺便说一下,如果您需要使用任何类型的测试双打(例如间谍),您可以通过定义包含测试的单独程序集来减少在单元测试项目中启用此选项的需要 - 将您的单元测试要求加倍,并在此测试双打组件上启用代码合同。