简体   繁体   English

NStack测试由于StackOverflowException而拒绝运行

[英]NUnit tests refusing to run due to StackOverflowException

I'm not sure what is causing the exception here at all. 我不知道到底是什么导致异常。

I had a number of tests which make use of NUnit TestCases, and these tests were all running fine with no issues. 我进行了许多使用NUnit TestCases的测试,并且这些测试运行良好,没有任何问题。 I then wrote an additional test which is almost identical to the others apart from a few variable values, and now none of my tests will run due to a StackOverflowException. 然后,我编写了一个额外的测试,除了几个变量值外,它几乎与其他测试完全相同,现在由于StackOverflowException,我的测试都无法运行。

[05/10/2018 10:10:00 Informational] ------ Run test started ------
[05/10/2018 10:10:00 Informational] NUnit Adapter 3.10.0.21: Test execution started
[05/10/2018 10:10:00 Informational] Running all tests in C:\test.dll
[05/10/2018 10:10:00 Informational] NUnit3TestExecutor converted 9 of 9 NUnit test cases
[05/10/2018 10:10:04 Error] The active test run was aborted. Reason: Process is terminated due to StackOverflowException.

[05/10/2018 10:10:04 Informational] ========== Run test finished: 0 run (0:00:04.661362) ==========

Tests in another test class will run, however none of the tests in this class will run even if I comment out the other tests. 另一个测试类中的测试将运行,但是即使我注释掉其他测试,该类中的任何测试也不会运行。

As you can see from the code below, most of the tests are structurally identical to the others, save for the variable names being passed as parameters and testcases. 从下面的代码中可以看到,大多数测试在结构上都与其他测试相同,除了将变量名作为参数和测试用例传递外。

[TestFixture]
    class FluentAddressValidatorTest
    {
        private FluentAddressValidator validator;

        [OneTimeSetUp]
        public void Setup()
        {
            validator = new FluentAddressValidator();
        }

        [Test]
        public void FluentAddressValidatorAllowsValidAddressObject()
        {
            //Arrange
            FluentAddressValidator validator = new FluentAddressValidator();

            Address address = new Address();
            address = new Address
            {
                HouseNum = "1",
                HouseName = "Big House",
                StreetName = "Street",
                Locality = "Locality",
                Town = "Town",
                County = "County",
                Postcode = "NE11NM"
            };

            //Act
            ValidationResult result = validator.Validate(address);

            //Assert
            Assert.That(result.IsValid, Is.True);
        }

        [TestCase("1$")]
        [TestCase("1.")]
        [TestCase("32A.")]
        [TestCase("1        ")]
        public void FluentAddressValidatorDisallowsInvalidHouseNumber(string houseNum)
        {
            Address address = new Address
            {
                HouseNum = houseNum,
                HouseName = "House name",
                StreetName = "Street",
                Locality = "Locality",
                Town = "Town",
                County = "County",
                Postcode = "NE11NM"
            };

            validator.ShouldHaveValidationErrorFor(a => a.HouseNum, address);
        }

        [TestCase("House.Name")]
        [TestCase("House name.")]
        [TestCase("Housè")]
        [TestCase("")]
        [TestCase(" ")]
        [TestCase("House name House name House name House name House name")]
        public void FluentAddressValidatorDisallowsInvalidHouseName(string houseName)
        {
            Address address = new Address
            {
                HouseNum = "1a",
                HouseName = houseName,
                StreetName = "Street",
                Locality = "Locality",
                Town = "Town",
                County = "County",
                Postcode = "NE11NM"
            };

            validator.ShouldHaveValidationErrorFor(a => a.HouseName, address);
        }

        [TestCase("Street.Name")]
        [TestCase("Street name.")]
        [TestCase("Strèet")]
        [TestCase("")]
        [TestCase(" ")]
        [TestCase("Street name Street name Street name Street name Street name")]
        public void FluentAddressValidatorDisallowsInvalidStreetName(string streetName)
        {
            Address address = new Address
            {
                HouseNum = "1a",
                HouseName = "house",
                StreetName = streetName,
                Locality = "Locality",
                Town = "Town",
                County = "County",
                Postcode = "NE11NM"
            };

            validator.ShouldHaveValidationErrorFor(a => a.StreetName, address);
        }

        [TestCase("'Locality'")]
        [TestCase("Locality.")]
        [TestCase("Lòcality")]
        [TestCase("")]
        [TestCase(" ")]
        [TestCase("Locality Locality Locality Locality Locality Locality ")]
        public void FluentAddressValidatorDisallowsInvalidLocality(string locality)
        {
            Address address = new Address
            {
                HouseNum = "1a",
                HouseName = "house",
                StreetName = "Street name",
                Locality = locality,
                Town = "Town",
                County = "County",
                Postcode = "NE11NM"
            };

            validator.ShouldHaveValidationErrorFor(a => a.Locality, address);
        }

        [TestCase("'Town'")]
        [TestCase("Town.")]
        [TestCase("Tòwn")]
        [TestCase("")]
        [TestCase(" ")]
        [TestCase("Town Town Town Town Town Town Town Town Town Town")]
        public void FluentAddressValidatorDisallowsInvalidTown(string town)
        {
            Address address = new Address
            {
                HouseNum = "1a",
                HouseName = "house",
                StreetName = "Street name",
                Locality = "Locality",
                Town = town,
                County = "County",
                Postcode = "NE11NM"
            };

            validator.ShouldHaveValidationErrorFor(a => a.Town, address);
        }

        [TestCase("'County'")]
        [TestCase("County.")]
        [TestCase("Còunty")]
        [TestCase("")]
        [TestCase(" ")]
        [TestCase("County County County County County County")]
        public void FluentAddressValidatorDisallowsInvalidCounty(string county)
        {
            Address address = new Address
            {
                HouseNum = "1a",
                HouseName = "house",
                StreetName = "Street name",
                Locality = "Locality",
                Town = "Town",
                County = county,
                Postcode = "NE11NM"
            };

            validator.ShouldHaveValidationErrorFor(a => a.County, address);
        }

        [TestCase("'Postc0de'")]
        [TestCase("Ne11111.")]
        [TestCase("NXXXX12")]
        [TestCase("NXXXX!£2")]
        [TestCase("")]
        [TestCase(" ")]
        [TestCase("NE1                  1BN")]
        public void FluentAddressValidatorDisallowsInvalidPostcode(string postcode)
        {
            Address address = new Address
            {
                HouseNum = "1a",
                HouseName = "house",
                StreetName = "Street name",
                Locality = "Locality",
                Town = "Town",
                County = "County",
                Postcode = postcode
            };

            validator.ShouldHaveValidationErrorFor(a => a.Postcode, address);
        }
    }

FluentAddressValidator FluentAddressValidator

public class FluentAddressValidator : AbstractValidator<Address>
    {
        private readonly string alphanumericalSpaceCaseInsensitiveRegex = "^[a-zA-Z0-9 ]*$";
        private readonly string alphabeticalSpaceCaseInsensitiveRegex = "^[a-zA-Z ]*$";

        public FluentAddressValidator()
        {
            RuleFor(a => a.HouseNum).NotEmpty().MaximumLength(8).Matches(alphanumericalSpaceCaseInsensitiveRegex) //Not empty string, alphanumeric, allows spaces
                .WithMessage("House number must be alphanumerical only.");
            RuleFor(a => a.HouseName).NotEmpty().MaximumLength(32).Matches(alphabeticalSpaceCaseInsensitiveRegex) //Not empty string, alphabetical, includes spaces
                .WithMessage("House name must be alphabetical only."); 
            RuleFor(a => a.StreetName).NotEmpty().MaximumLength(32).Matches(alphabeticalSpaceCaseInsensitiveRegex) //Not empty string, alphabetical, includes spaces
                .WithMessage("Street name must be alphabetical only."); 
            RuleFor(a => a.Locality).NotEmpty().MaximumLength(32).Matches(alphabeticalSpaceCaseInsensitiveRegex) //Not empty string, alphabetical, includes spaces
                .WithMessage("Locality must be alphabetical only."); 
            RuleFor(a => a.Town).NotEmpty().MaximumLength(32).Matches(alphabeticalSpaceCaseInsensitiveRegex) //Not empty string, alphabetical, includes spaces
                .WithMessage("Town must be alphabetical only."); 
            RuleFor(a => a.County).NotEmpty().MaximumLength(32).Matches(alphabeticalSpaceCaseInsensitiveRegex) //Not empty string, alphabetical, includes spaces
                .WithMessage("County must be alphabetical only."); 
            RuleFor(a => a.Postcode).NotEmpty().MaximumLength(16).Must(Common.IsValidUkPostcode) //Not empty string, is valid uk postcode
                .WithMessage("Postcode must follow valid UK postcode format."); 
        }

    }

IsValidUkPostcode IsValidUkPostcode

public static bool IsValidUkPostcode(string postcode)
        {
            postcode = postcode.Replace(" ", string.Empty);
            postcode = postcode.ToUpper();

            Regex r = new Regex(@"([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([A-Za-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9][A-Za-z]?))))\s?[0-9][A-Za-z]{2})");

            if (r.IsMatch(postcode))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

The cause of the StackOverflowException was due to the presence of Properties within the Address class that accidently made calls to itself recursively. StackOverflowException的原因是由于Address类中存在Properties,导致意外递归地对其自身进行调用。 This was not an issue with FluentValidation or NUnit. 这与FluentValidation或NUnit无关。

For example: 例如:

public string Street
{
    get
    {
        return Street;
    }
    set
    {
        Street = value;
    }
}

This causes recursion and eventually will cause a stack overflow. 这将导致递归,并最终将导致堆栈溢出。 To prevent this, have a private backing field that the property can delegate the data to. 为避免这种情况,请使用私有后备字段,该属性可以将数据委托给该字段。

private string street;

public string Street
{
    get
    {
        return this.street;
    }
    set
    {
        this.street = value;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM