Two of the class properties have the following annotations:
[Key]
[Column]
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[MaxLength(25)]
public string Name { get; set; }
I understand that testing Key, Column and Required attributes is no longer a unit test, it's an integration test as it would depend on the underlying database, but how do you go about testing MaxLength(25) attribute?
One of the alternatives that I can think of, is to add a code contract into the property.
Update
As suggested, I wrote the following helper:
public class AttributeHelper <T> where T : class
{
private Type GivenClass
{
get { return typeof (T); }
}
public bool HasAnnotation(Type annotation)
{
return GivenClass.GetCustomAttributes(annotation, true).Single() != null;
}
public bool MethodHasAttribute(Type attribute, string target)
{
return GivenClass.GetMethod(target).GetCustomAttributes(attribute, true).Count() == 1;
}
public bool PropertyHasAttribute(Type attribute, string target)
{
return GivenClass.GetProperty(target).GetCustomAttributes(attribute, true).Count() == 1;
}
}
I have then tested my helper:
[TestMethod]
public void ThisMethod_Has_TestMethod_Attribute()
{
// Arrange
var helper = new AttributeHelper<AttributeHelperTests>();
// Act
var result = helper.MethodHasAttribute(typeof (TestMethodAttribute), "ThisMethod_Has_TestMethod_Attribute");
// Assert
Assert.IsTrue(result);
}
Everything works fine, apart from the fact that methods and properties must be public in order for me to use reflection. I can't think of any cases where I had to add attributes to the private properties/methods.
And then testing the EF annotations:
public void IdProperty_Has_KeyAttribute()
{
// Arrange
var helper = new AttributeHelper<Player>();
// Act
var result = helper.PropertyHasAttribute(typeof (KeyAttribute), "Id");
// Assert
Assert.IsTrue(result);
}
I understand that testing Key, Column and Required attributes is no longer a unit test, it's an integration test as it would depend on the underlying database
How is that so? You can test whether Id property is marked with all those attributes just fine. And it falls into unit-test category.
[Test]
public void Id_IsMarkedWithKeyAttribute()
{
var propertyInfo = typeof(MyClass).GetProperty("Id");
var attribute = propertyInfo.GetCustomAttributes(typeof(KeyAttribute), true)
.Cast<KeyAttribute>()
.FirstOrDefault();
Assert.That(attribute, Is.Not.Null);
}
This way you can assure your properties are marked with any attribute you can think of. Sure, this involves some reflection work but that's how you test attribute marking.
Related
I have the following class:
public class Foo
{
public Foo(string id,
string name,
string? homeTown = null,
IEnumerable<string>? someCollection = null)
{
Id = id;
Name = name;
HomeTown = homeTown;
SomeCollection = someCollection;
}
public string Id { get; set; }
public string Name {get; set;}
public string? HomeTown {get; set;}
public IEnumerable<string>? SomeCollection {get; set;}
}
I want to create a mock with AutoFixture without filling HomeTown and SomeCollection.
But when I try to create it like this, the properties still get filled!
Fixture fixture = new Fixture();
var dto = fixture.Build<Foo>()
.Without(x => x.HomeTown)
.Without(x => x.SomeCollection)
.Create();
If I add another constructor without hometown and somecollection - it will work, but I don't want to add another constructor just to satisfy the tests.
Why is this behaviour? Is this some kind of a bug in AutoFixture?
Is there a way to solve it?
As far as I can tell, this is the intended behavior of AutoFixture, and the way it is pushing developers toward a better design.
AutoFixture is a (opinionated) tool for TDD, built around the 80-20 rule, so it does make a few assumptions about how you will design your code, and it implements mostly features that are used in most common situations.
That said it is also a very open-ended tool that allows for a lot of flexibility. This means you can tell it to omit any optional parameters.
You could implement that by creating a builder that returns the default value set for the optional parameter and then omit all auto properties.
class OptionalParameterSpecification : IRequestSpecification
{
public bool IsSatisfiedBy(object request)
=> request is ParameterInfo parameterInfo
&& parameterInfo.IsOptional;
}
class DefaultValueParameterBuilder : ISpecimenBuilder
{
private readonly IRequestSpecification specification;
public DefaultValueParameterBuilder(IRequestSpecification specification)
{
this.specification = specification
?? throw new ArgumentNullException(nameof(specification));
}
public object Create(object request, ISpecimenContext context)
{
if (!this.specification.IsSatisfiedBy(request)) return new NoSpecimen();
if (request is not ParameterInfo parameterInfo) return new NoSpecimen();
return parameterInfo.DefaultValue;
}
}
Using the builder above, your test should look like this.
[Fact]
public void Bar()
{
var fixture = new Fixture();
fixture.Customizations.Add(
new DefaultValueParameterBuilder(
new OptionalParameterSpecification()));
fixture.Customize<Foo>(c => c.OmitAutoProperties());
var foo = fixture.Create<Foo>();
Assert.NotNull(foo.Id);
Assert.NotNull(foo.Name);
Assert.Null(foo.HomeTown);
Assert.Null(foo.SomeCollection);
}
I need to test simple class like this:
public class SomeEntity {
public int Id { get; set; }
public string Name { get; set; }
}
And I want to write test using mock of this class objects like this:
var someMock = new Moq.Mock<SomeEntity>();
someMock.SetupGet(x => x.Id).Returns(12345678);
someMock.SetupGet(x => x.Name).Returns(It.IsIn(someList));
As you know Moq framework require interface or virtual methods to create proxy object. So my question is: how can I mock my entity class without implementing interface or marking properties with virtual?
UPDATE: what is the most desired result of all this is to substitute moq object to my unit test with multiple possible combinations of properties.
UPDATE 2: it looks like I don't need to mock my entity class, I just need to iterate via all possible combinations using It.IsIn(someList):
var someEntity = new SomeEntity {
Id = 12345678,
Name = It.IsIn(someList)
}
You wouldn't need to mock this to be able to test with it.
You should be able to test with SomeEntity in its current state directly (and test it itself but testing auto properties seems like a waste of effort).
If you create an interface of ISomeEntity that SomeEntity implements then you would be able to mock that inside anything that consumes it. Then you would be able to test the behavior of methods that an ISomeEntity is passed into.
As you've said Moq requires it to be an interface or virtual methods to work on.
public class SomeEntity : ISomeEntity {
public int Id { get; set; }
public string Name { get; set; }
}
public interface ISomeEntity {
int Id { get; set; }
string Name { get; set; }
}
Then
var someMock = new Mock<ISomeEntity>();
someMock.SetupGet(x => x.Id).Returns(12345678);
someMock.SetupGet(x => x.Name).Returns(It.IsIn(someList));
var result = somethingelse.Act(someMock.Obect);
If your object is as logic free as in the example then there is no need to go to Mock
var item = new SomeEntity();
item .Id = 12345678;
item .Name = "some name";
var result = somethingelse.Act(item);
What benefit are you trying to get via using a mock here? If you are trying to run through the list and verfify for each item in it, It.IsIn won't do that (even attached to a mock) all it will check is that the value assigned to the mock is in the list of allowed values.
This breaks the single assert for each test maxim but, I think this is what you want:
var item = new SomeEntity();
foreach (var name in someList)
{
item .Id = 12345678;
item .Name = name ;
var result = somethingelse.Act(item);
// Assert
}
I have been using RhinoAutoMocker for unit testing, and it works very well in almost all cases. I'm currently having trouble figuring out is how to use it when the Class Under Test has primitive constructor arguments.
Let's say I have two classes defined as such:
public class AddAnswerValidator : BaseValidator
{
public AddAnswerValidator(Answer answerToAdd,
IAnswerRepository answerRepository)
{
...some code
}
public override bool Validates()
{
...some code
}
}
public class RemoveAnswerValidator : BaseValidator
{
public RemoveAnswerValidator(int answerIDToRemove,
IAnswerRepository answerRepository)
{
...some code
}
public override bool Validates()
{
...some code
}
}
An example test for each are as follows:
[Test]
public void AddAnswerValidatorTests_Validates_ValidInput_ReturnsTrue()
{
var autoMocker = new RhinoAutoMocker<AddAnswerValidator>();
var fakeAnswer = new Answer();
autoMocker.Inject<Answer>(fakeAnswer);
var result = autoMocker.ClassUnderTest.Validates();
Assert.IsTrue(result);
}
[Test]
public void RemoveAnswerValidatorTests_Validates_ValidInput_ReturnsTrue()
{
var autoMocker = new RhinoAutoMocker<RemoveAnswerValidator>();
var fakeAnswerID = 1;
autoMocker.Inject<int>(fakeAnswerID);
var result = autoMocker.ClassUnderTest.Validates();
Assert.IsTrue(result);
}
The first test (for AddAnswerValidator) works fine. The second test (for RemoveAnswerValidator) fails with a StructureMap 202 Error "No default instance defined for plugin family RemoveAnswerValidator" error. I'm working under the assumption that the second test is failing because StructureMap isn't resolving the integer constructor argument.
I've read through this post regarding RhinoAutoMocker Injection for collections and I've been tracing through the source code on GitHub, but I don't understand why the primitive value isn't being injected.
I've even tried substituting some of the overloaded Inject methods available on the container object such as:
autoMocker.Inject<int>(fakeAnswerID);
with
autoMocker.Container.Inject<int>("answerIDToRemove", fakeAnswerID);
but using the name of the constructor argument doesn't produce any different results.
--
In the long run, this isn't a huge problem since I can always just create an instance of the Class Under Test and create my own mocks, it would just be nice to be able to use a consistent methodology across all of my tests.
I know, it's a little bit too late, but i had the same problem and managed to solve it with integer parameter:
var autoMocker = new RhinoAutoMocker<RemoveAnswerValidator>();
automocker.Container.Configure(c=>
c.For<RemoveAnswerValidator>()
.Use<RemoveAnswerValidator>()
.Ctor<int>()
.Is(1));
While I never did find a way to inject a primitive using AutoMocker, I ended up working around the problem by creating a parameter object and injecting that instead.
The parameter object then includes the necessary primitives as a properties, in addition to the other (former) parameters. The example above would be changed to:
public class RemoveAnswerValidator : BaseValidator
{
public RemoveAnswerValidator(RemoveAnswerValidatorParameters parms)
{
...some code
}
public override bool Validates()
{
...some code
}
}
public class RemoveAnswerValidatorParameters
{
public int AnswerID { get; set; }
public IAnswerRepository AnswerRepository { get; set; }
}
(Then in the test class)
[Test]
public void RemoveAnswerValidatorTests_Validates_ValidInput_ReturnsTrue()
{
var autoMocker = new RhinoAutoMocker<RemoveAnswerValidator>();
var fakeAnswerParameters = new FakeAnswerParameters()
{
AnswerID = 1,
AnswerRepository = autoMocker.Get<IAnswerRepository>()
};
autoMocker.Inject<RemoveAnswerValidatorParameters>(fakeAnswer);
var result = autoMocker.ClassUnderTest.Validates();
Assert.IsTrue(result);
}
I have the following simple class Data annotation to control the area of phone number:
public class PhoneAreaAttribute : ValidationAttribute, IClientValidatable
{
public const string ValidInitNumber = "0";
public const int MinLen = 2;
public const int MaxLen = 4;
public override bool IsValid(object value)
{
var area = (string)value;
if (string.IsNullOrWhiteSpace(area))
{
return true;
}
if (area.StartsWith(PhoneAreaAttribute.ValidInitNumber))
{
return false;
}
if (!Regex.IsMatch(area, #"^[\d]+$"))
{
return false;
}
if (!area.LengthBetween(PhoneAreaAttribute.MinLen, PhoneAreaAttribute.MaxLen))
{
return false;
}
return true;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
ValidationType = "phoneArea",
};
yield return rule;
}
}
I do not know how it would be a correct unit test for this class.
thanks.
Okay, basically testing an attribute is the same as testing any regular class. I took your class and reduced it a little bit so I could run it (you created some extension methods, which I didn't want to recreate). Below you find this class definition.
public class PhoneAreaAttribute : ValidationAttribute
{
public const string ValidInitNumber = "0";
public override bool IsValid(object value)
{
var area = (string)value;
if (string.IsNullOrEmpty(area))
{
return true;
}
if (area.StartsWith(PhoneAreaAttribute.ValidInitNumber))
{
return false;
}
return true;
}
}
Note beforehand: some of my naming conventions for unit tests might differ from the ones you use (there are a few out there).
Now we will create a Unit Test. I understood that you already have a Test Project, if you don't have one, just create one. In this test project, you will create a new unit test (Basic Unit Test), let's name it PhoneAreaAttributeTest.
As good practice, I create a test initialiser to create all shared "resources", in this case a new instance of the PhoneAreaAttribute class. Yes, you can just create an instance, like you are used to with "regular" classes (as a matter of fact, there isn't that much difference between "regular" classes and your attribute class).
Now we are ready to start writing the tests for the methods. Basically you will want to handle all possible scenarios. I will show you here two scenarios that are possible in my (reduced) IsValid method. First I will see whether the given object parameter can be cased to a string (this is a first scenario / TestMethod). Second I will see whether the path of "IsNullOrEmpty" is properly handled (this is a second scenario / TestMethod).
As you can see, it is just a regular unit test. These are just the very basics. If you still have questions, I would like to also suggest you to read some tutorials.
Here is the PhoneAreaAttributeTest test class:
[TestClass]
public class PhoneAreaAttributeTest
{
public PhoneAreaAttribute PhoneAreaAttribute { get; set; }
[TestInitialize]
public void PhoneAreaAttributeTest_TestInitialise()
{
PhoneAreaAttribute = new PhoneAreaAttribute();
}
[TestMethod]
[ExpectedException(typeof(InvalidCastException))]
public void PhoneAreaAttributeTest_IsValid_ThrowsInvalidCastException()
{
object objectToTest = new object();
PhoneAreaAttribute.IsValid(objectToTest);
}
[TestMethod]
public void PhoneAreaAttributeTest_IsValid_NullOrEmpty_True()
{
string nullToTest = null;
string emptoToTest = string.Empty;
var nullTestResult = PhoneAreaAttribute.IsValid(nullToTest);
var emptyTestResult = PhoneAreaAttribute.IsValid(emptoToTest);
Assert.IsTrue(nullTestResult, "Null Test should return true.");
Assert.IsTrue(emptyTestResult, "Empty Test should return true.");
}
}
When considering how to "correctly" test this class, consider the following:
The cyclomatic complexity (CC) of IsValid is 5.
The method relies on two other methods IsNullOrWhiteSpace and LengthBetween. I believe both of these have an additional CC of 2.
There is the chance of throwing an InvalidCastException. This represents another potential test case.
In total, you have potentially 8 cases in which you need to test. Using xUnit.net and Fluent Assertions* (you could do something similar in NUnit as well), you could write the following unit tests to "correctly" test this method:
public class PhoneAreaAttributeTests
{
[Theory]
[InlineData("123", true)]
[InlineData(" ", true)]
[InlineData(null, true)]
public void IsValid_WithCorrectInput_ReturnsTrue(
object value, bool expected)
{
// Setup
var phoneAreaAttribute = CreatePhoneAreaAttribute();
// Exercise
var actual = phoneAreaAttribute.IsValid(value);
// Verify
actual.Should().Be(expected, "{0} should be valid input", value);
// Teardown
}
[Theory]
[InlineData("012", false)]
[InlineData("A12", false)]
[InlineData("1", false)]
[InlineData("12345", false)]
public void IsValid_WithIncorrectInput_ReturnsFalse(
object value, bool expected)
{
// Setup
var phoneAreaAttribute = CreatePhoneAreaAttribute();
// Exercise
var actual = phoneAreaAttribute.IsValid(value);
// Verify
actual.Should().Be(expected, "{0} should be invalid input", value);
// Teardown
}
[Fact]
public void IsValid_UsingNonStringInput_ThrowsExcpetion()
{
// Setup
var phoneAreaAttribute = CreatePhoneAreaAttribute();
const int input = 123;
// Exercise
// Verify
Assert.Throws<InvalidCastException>(
() => phoneAreaAttribute.IsValid(input));
// Teardown
}
// Simple factory method so that if we change the
// constructor, we don't have to change all our
// tests reliant on this object.
public PhoneAreaAttribute CreatePhoneAreaAttribute()
{
return new PhoneAreaAttribute();
}
}
*I like using Fluent Assertions, and in this case it helps because we can specify a message to let us know when an assert fails, which one is the failing assertion. These data-driven tests are nice in that they can reduce the number of similar test methods we would need to write by grouping various permutations together. When we do this it is a good idea to avoid Assertion Roulette by the custom message as explained. By the way, Fluent Assertions can work with many testing frameworks.
I'm using Moq and I have the following interface:
public interface IGameBoard : IEnumerable<PieceType>
{
...
}
public class GameBoardNodeFactory
{
public virtual GameBoardNode Create (int row, int column, IGameBoard gameBoard)
{
...
}
}
Then I have a test like this:
var clonedGameBoardMock = new Mock<IGameBoard> (MockBehavior.Loose);
var gameBoardNodeFactoryMock = new Mock<GameBoardNodeFactory> ();
gameBoardNodeFactoryMock.Setup (x =>
x.Create (
position.Row,
position.Column,
clonedGameBoardMock.Object)).Returns (new GameBoardNode { Row = position.Row, Column = position.Column });
But then gameBoardNodeFactoryMock.Object.Create (position.Row, position.Column, clonedGameBoardMock.Object) throws a NullReferenceException. I tried to create a mock for the IGameBoard such that it doesn't extend IEnumerable<PieceType> interface and then it works.
Any help is appreciated.
You would need to create a Setup for GetEnumerator() if it's being called. Something like:
var mockPieces = new List<PieceType>;
clonedGameBoardMock.Setup(g => g.GetEnumerator()).Returns(mockPieces.GetEnumerator());
Note sure if that's the issue in this case, but worth noting if you ever need to mock IEnumerable<T>.
The answer by #DanBryant was also the key to our solution. However, the enumerator in that case might be accidentally reused. Instead, I suggest using:
clonedGameBoardMock.Setup(g => g.GetEnumerator()).Returns(() => mockPieces.GetEnumerator());
Here's a full repro (new class library using NUnit 2.6.4 and Moq 4.2):
public interface IMyThing<T> : IEnumerable<T>
{
string Name { get; set; }
IMyThing<T> GetSub<U>(U key);
}
public interface IGenericThing
{
string Value { get; set; }
}
public class Pet
{
public string AnimalName { get; set; }
}
public class Unit
{
public IEnumerable<Pet> ConvertInput(IMyThing<IGenericThing> input)
{
return input.GetSub("api-key-123").Select(x => new Pet { AnimalName = x.Value });
}
}
[TestFixture]
public class Class1
{
[Test]
public void Test1()
{
var unit = new Unit();
Mock<IMyThing<IGenericThing>> mock = new Mock<IMyThing<IGenericThing>>();
Mock<IMyThing<IGenericThing>> submock = new Mock<IMyThing<IGenericThing>>();
var things = new List<IGenericThing>(new[] { new Mock<IGenericThing>().Object });
submock.Setup(g => g.GetEnumerator()).Returns(() => things.GetEnumerator());
mock.Setup(x => x.GetSub(It.IsAny<string>())).Returns(submock.Object);
var result = unit.ConvertInput(mock.Object);
Assert.That(result, Is.Not.Null.And.Not.Empty);
Assert.That(result, Is.Not.Null.And.Not.Empty); // This would crash if the enumerator wasn't returned through a Func<>...
}
}
For what it's worth / to make this question pop up to that one lone Googler with the same problem I had: the above is an abstracted version of the Couchbase .NET client's IView<T> interface, which also implements IEnumerable<T>.
A null reference in this situation usually means your setup was never met. Meaning it was never called with the exact values you set it up for. To debug this I would make your match less constraining by using It.IsAny() and so on to make sure the test will match on any call to the mocked function. In most cases this is good enough. Any reason why your are trying to match on specific values?
Okay if anyone is interested, I updated Moq to version 4 and now everything works as expected.