I was hoping that by using AutoFixture and NSubstitue, I could use the best of what each have to provide. I have had some success using NSubstitute on its own, but I am completely confused on how to use it in combination with AutoFixture.
My code below shows a set of things I am trying to accomplish, but my main goal here is to accomplish the following scenario: Test the functionality of a method.
- I expect the constructor to be called with random values (except maybe one - please read point 2.).
- Either during construction or later, I want to change value of a property -
Data. - Next call
Executeand confirm the results
The test that I am trying to get working is: "should_run_GetCommand_with_provided_property_value"
Any help or reference to an article that shows how NSubstitue and AutFixture SHOULD be used, would be great.
Sample Code:
using FluentAssertions;
using NSubstitute;
using Ploeh.AutoFixture;
using Ploeh.AutoFixture.AutoNSubstitute;
using Xunit;
namespace RemotePlus.Test
{
public class SimpleTest
{
[Fact]
public void should_set_property_to_sepecified_value()
{
var sut = Substitute.For<ISimple>();
sut.Data.Returns("1,2");
sut.Data.Should().Be("1,2");
}
[Fact]
public void should_run_GetCommand_with_provided_property_value()
{
/* TODO:
* How do I create a constructor with AutoFixture and/or NSubstitute such that:
* 1. With completely random values.
* 2. With one or more values specified.
* 3. Constructor that has FileInfo as one of the objects.
*
* After creating the constructor:
* 1. Specify the value for what a property value should be - ex: sut.Data.Returns("1,2");
* 2. Call "Execute" and verify the result for "Command"
*
*/
// Arrange
var fixture = new Fixture().Customize(new AutoNSubstituteCustomization());
// var sut = fixture.Build<Simple>().Create(); // Not sure if I need Build or Freeze
var sut = fixture.Freeze<ISimple>(); // Note: I am using a Interface here, but would like to test the Concrete class
sut.Data.Returns("1,2");
// Act
sut.Execute();
// Assert (combining multiple asserts just till I understand how to use NSubstitue and AutoFixture properly
// sut.Received().Execute();
sut.Data.Should().Be("1,2");
sut.Command.Should().Be("1,2,abc");
// Fails with : FluentAssertions.Execution.AssertionFailedExceptionExpected string to be "1,2,abc" with a length of 7, but "" has a length of 0.
}
}
public class Simple : ISimple
{
// TODO: Would like to make this private and use the static call to get an instance
public Simple(string inputFile, string data)
{
InputFile = inputFile;
Data = data;
// TODO: Would like to call execute here, but not sure how it will work with testing.
}
// TODO: Would like to make this private
public void Execute()
{
GetCommand();
// Other private methods
}
private void GetCommand()
{
Command = Data + ",abc";
}
public string InputFile { get; private set; }
public string Data { get; private set; }
public string Command { get; private set; }
// Using this, so that if I need I can easliy switch to a different concrete class
public ISimple GetNewInstance(string inputFile, string data)
{
return new Simple(inputFile, data);
}
}
public interface ISimple
{
string InputFile { get; } // TODO: Would like to use FileInfo instead, but haven't figured out how to test. Get an error of FileNot found through AutoFixture
string Data { get; }
string Command { get; }
void Execute();
}
}
I haven't really used AutoFixture much, but based on some reading and a bit of trial and error, I think you're misinterpreting what it will and won't do for you. At a basic level, it'll let you create a graph of objects, filling in values for you based around the objects constructors (and possibly properties but I haven't looked into that).
Using the NSubstitute integration doesn't make all of the members of your class into NSubstitute instances. Instead, it gives the fixture framework the ability to create abstract / interface types as Substitutes.
Looking at the class you're trying to create, the constructor takes two
stringparameters. Neither of these is an abstract type, or an interface so AutoFixture is just going to generate some values for you and pass them in. This is AutoFixture's default behaviour and based on the answer linked to by @Mark Seemann in the comments this is by design. There are various work arounds proposed by him there that you can implement if it's really important for you to do so, which I won't repeat here.You've indicated in your comments that you really want to pass a
FileInfointo your constructor. This is causing AutoFixture a problem, since its constructor takes a string and consequently AutoFixture is supplying a random generated string to it, which is a non-existent file so you get an error. This seems like a good thing to try to isolate for testing so is something that NSubstitute might be useful for. With that in mind, I'm going to suggest that you might want to rewrite your classes and test something like this:First up create a wrapper for the
FileInfoclass (note, depending on what you're doing you might want to actually wrap the methods from FileInfo that you want, rather than exposing it as a property so that you can actually isolate yourself from the filesystem but this will do for the moment):Use this in your
ISimpleinterface instead of astring(notice I've removed Execute since you don't seem to want it there):Write
Simpleto implement the interface (I haven't tackled your private constructor issue, or your call to Execute in the constructor):And then the test:
I'm not using fluent asserts above, but you should be able to translate...