it seems comments can't support code
Lets say I call a method (e.g. SaveTicket) and have used constructor(e.g. Repository, Logging) to inject various mock interfaces. If that method calls another object and creates a non-primitive object inside that method. Is there any easy way to test the values of that non-primitive object?
I guess trying to replace that non-primitive object with property and injecting is possible, or Using LastCall.Constraints. Is there a better way?
Here is an example - in the below example - in order to verify
Repository.save(t);
is called with correct values of t I can
Do lastcall.constraints
lastcall.ignorearguments
Is there a better way?
CreateMyTicket(int ticketnumber, string name)
{
ticketobject t = new ticketObject(ticketnumber, name);
t.upgrade = ticketnumber+2;
Repository.save(t);
}
Let's take an example. Suppose that you have the following class and you want to unit test the CreateMyTicket method:
public class ClassToTest
{
public IRepository Repository { get; private set; }
public ClassToTest(IRepository repository)
{
Repository = repository;
}
public void CreateMyTicket(int ticketnumber, string name)
{
var t = new TicketObject(ticketnumber, name);
t.Upgrade = ticketnumber + 2;
Repository.Save(t);
}
}
This assumes that we have an IRepository interface:
public interface IRepository
{
void Save(TicketObject t);
}
and here's how a sample unit test could look like:
[TestMethod]
public void CreateMyTicketTest()
{
// arrange
var repositoryStub = MockRepository.GenerateStub<IRepository>();
var sut = new ClassToTest(repositoryStub);
var ticketNumber = 5;
var name = "John";
// act
sut.CreateMyTicket(ticketNumber, name);
// assert
repositoryStub.AssertWasCalled(
x => x.Save(
Arg<TicketObject>.Matches(t =>
t.Upgrade == 7 &&
t.Name == name &&
t.TicketNumber == ticketNumber
)
)
);
}
You should only test which methods was called on mocked dependencies (Repository, Logging). Verifying objects, returned from mocks, give you nothing (because you verify what you just created manually and set as return result).
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 work an an automation team designing tests for electronic components. One thing our framework sorely needs is a single source point for our driver objects for the various pieces of test equipment at a workbench (right now, driver object creation is very wild-west).
Basically, the idea would be there would be one object, constructed based on a configuration file(s), which is the single place all other test code looks to to get the driver objects, based on a name string. I'll call it a "DriverSource" here.
The problem is, these drivers do not present similar interfaces at all. One might be a power supply (with methods like "SetVoltage" and "SetCurrentLimit"), while another might be a digital multimeter (with methods like "ReadVoltage" or "ReadCurrent").
The best solution I've come up with is to have a method with the following declaration:
public object GetDriver(string name);
Then, the test code using my "DriverSource" object would call that method, and then cast the System.Object to the correct driver type (or more accurately, the correct driver interface, like IPowerSupply).
I think casting like that is acceptable because whatever test code is about to use this driver had better know what the interface is. But I was hoping to get some input on whether or not this is an anti-pattern waiting to bite me. Any better pattern for solving this issue would also be greatly appreciated.
A final note: I think this is obvious, but performance is essentially a non-issue for this problem. Fetching the drivers is something will happen less than 100 times in a test run that can last hours.
If you already know the type and you're going to cast to an interface or class anyway, a better approach would be to hand the method call a type parameter.
public T GetDriver<T>(string name);
You can then use a Factory pattern to return you an object of the appropriate type from the method.
public T GetDriver<T>(string name)
{
switch(typeof(T).Name)
{
case "Foo":
// Construct and return a Foo object
case "Bar":
// Construct and return a Bar object
case "Baz":
// Construct and return a Baz object
default:
return default(T);
}
}
Usage:
var driver = GetDriver<Foo>(someString); // Returns a Foo object
If you really want to make this generic, I would use a factory pattern.
Lets start off by identifying the type structure:
public interface IDriver
{
}
public interface IPowerSupply : IDriver
{
void SetVoltage();
void SetCurrent();
}
public interface IMultimeter : IDriver
{
double MeasureVoltage();
}
Which you can add to or remove from as needed. Now we need a way for the factory to auto-discover the correct types and provide the configuration information to it. So lets create a custom attribute:
public class DriverHandlerAttribute : Attribute
{
public Type DriverType { get; set; }
public string ConfigurationName { get; set; }
}
And then we need a place to store configuration data. This type can contain whatever you want, like a dictionary of keys/values that are loaded from configuration files:
public class Configuration
{
public string DriverName { get; set; }
public string OtherSetting { get; set; }
}
Finally we can create a driver. Lets create an IPowerSupply:
[DriverHandler(DriverType = typeof(IPowerSupply), ConfigurationName="BaseSupply")]
public class BasePowerSupply : IPowerSupply
{
public BasePowerSupply(Configuration config) { /* ... */ }
public void SetVoltage() { /* ... */ }
public void SetCurrent() { /* ... */ }
}
The important part is that it is decorated with the attribute and that it has a constructor (although I created the factory so that it can use default constructors too):
public static class DriverFactory
{
public static IDriver Create(Configuration config)
{
Type driverType = GetTypeForDriver(config.DriverName);
if (driverType == null) return null;
if (driverType.GetConstructor(new[] { typeof(Configuration) }) != null)
return Activator.CreateInstance(driverType, config) as IDriver;
else
return Activator.CreateInstance(driverType) as IDriver;
}
public static T Create<T>(Configuration config) where T : IDriver
{
return (T)Create(config);
}
private static Type GetTypeForDriver(string driverName)
{
var type = (from t in Assembly.GetExecutingAssembly().GetTypes()
let attrib = t.GetCustomAttribute<DriverHandlerAttribute>()
where attrib != null && attrib.ConfigurationName == driverName
select t).FirstOrDefault();
return type;
}
}
So to use this, you would read in the configuration data (loaded from XML, read from a service, files, etc). You can then create the driver like:
var driver = DriverFactory.Create(configuration);
Or if you are using the generic method and you know the configuration is for a power supply, you can call:
var driver = DriverFactory.Create<IPowerSupply>(configuration);
And when you run your tests, you can verify that you get the right data back, for example, in your test method:
Assert.IsTrue(driver is IPowerSupply);
Assert.IsTrue(driver is BaseSupply);
Assert.DoesWhatever(((IPowerSupply)driver).SetVoltage());
And so-on and so-forth.
I would go with this code:
public T GetDriver<T>(string name)
{
return ((Func<string, T>)_factories[typeof(T)])(name);
}
The _factories object looks like this:
private Dictionary<Type, Delegate> _factories = new Dictionary<Type, Delegate>()
{
{ typeof(Foo), (Delegate)(Func<string, Foo>)(s => new Foo(s)) },
{ typeof(Bar), (Delegate)(Func<string, Bar>)(s => new Bar()) },
{ typeof(Baz), (Delegate)(Func<string, Baz>)(s => new Baz()) },
};
Basically the _factories dictionary contains all of the code to create each object type based on string parameter passed in. Note that in my example above the Foo class takes s as a constructor parameter.
The dictionary can also then be modified at run-time to suite your needs without needing to recompile code.
I would even go one step further. If you define this factory class:
public class Factory
{
private Dictionary<Type, Delegate> _factories = new Dictionary<Type, Delegate>();
public T Build<T>(string name)
{
return ((Func<string, T>)_factories[typeof(T)])(name);
}
public void Define<T>(Func<string, T> create)
{
_factories.Add(typeof(T), create);
}
}
You can then write this code:
var drivers = new Factory();
drivers.Define(s => new Foo(s));
drivers.Define(s => new Bar());
drivers.Define(s => new Baz());
var driver = drivers.Build<Foo>("foo");
I like that even better. It's strongly-typed and easily customized at run-time.
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);
}
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.
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.