I want a unit test that verifies 2 function calls happen in the correct order. In the example, the first function encrypts a file and saves it to the file system, and the second function sends the encrypted file to a 3rd party processor (via FTP).
I am using NSubstitute as the mock framework and FluentAssertions to aid in test verification. It does not seem like this is something you can achieve with NSubstitute out of the box.
public void SendUploadToProcessor(Stream stream, string filename)
{
var encryptedFilename = FilenameBuilder.BuildEncryptedFilename(filename);
FileEncrypter.Encrypt(stream, filename, encryptedFilename);
FileTransferProxy.SendUpload(encryptedFilename);
}
[TestMethod, TestCategory("BVT")]
public void TheEncryptedFileIsSent()
{
var stream = new MemoryStream();
var filename = Fixture.Create<string>();
var encryptedFilename = Fixture.Create<string>();
FilenameBuilder
.BuildEncryptedFilename(Arg.Any<string>())
.Returns(encryptedFilename);
Sut.SendUploadToProcessor(stream, filename);
// Something here to verify FileEncrypter.Encrypt() gets called first
FileTransferProxy
.Received()
.SendUpload(encryptedFilename);
}
Try Received.InOrder in the NSubstitute.Experimental namespace.
Something like this (I haven't tested this):
Received.InOrder(() => {
FileEncrypter.Encrypt(stream, filename, encryptedFilename);
FileTransferProxy.SendUpload(encryptedFilename);
});
If you're not comfortable relying on experimental functionality, you will need to set up callbacks to store calls in order, then assert on that.
var calls = new List<string>(); //or an enum for different calls
FileEncrypter.When(x => x.Encrypt(stream, filename, encryptedFilename))
.Do(x => calls.Add("encrypt"));
FileTransferProxy.When(x => x.SendUpload(encryptedFilename))
.Do(x => calls.Add("upload"));
// Act
// Assert calls contains "encrypt","upload" in the correct order
If you do end up trying Received.InOrder, please leave some feedback on the discussion group. If we get some feedback about it working well for others then we can promote it to the core namespace.
Although it is not an answer persee, but verifying the explicit order as part of a unit test is bad practice. You should never test the implementation details. Just make sure the input is properly converted to the output and add some alternative scenarios that basically proof the expected behavior. That's the precise reason why this functionality was deprecated in RhinoMocks and that FakeItEasy doesn't even support it.
Related
New to testing and React Redux, so I may be conflating a few issues here. I will only present one example, but I have tried many different combinations of mount(), shallow(), instance(), stub, spy and more.
Given a component, where setFooData() updates redux state and Foo.props.data:
const mapDispatchToProps = (dispatch, props) => ({
setFooData(fooId, data) {
dispatch(Actions.setFooData(fooId, data));
},
});
...
return (
<div fooId={this.props.fooId}>
<Foo {...fooProps}/>
</div>
);
I would like to write some tests around the conditions under which setFooData() is called, namely conditions in lifecycle methods like componentDidMount() and componentWillReceiveProps().
Because setFooData() involves server calls and more, and because these tests merely concern the view layer and how the component renders as a result of Foo.props.data being set eventually by setFooData(), setFooData() seems like a good candidate for stub.
Therefore, Enzyme's shallow(), rather than mount(), seems appropriate, correct? In any case, when I try to stub setFooData():
let wrapper = return shallow(<Foo {...props}/>);
let stub = sinon.stub(wrapper.instance(), 'setFooData');
I receive the error:
Attempted to wrap undefined property setFooData as function
Upon inspection, wrapper.instance() yields an object where setFooData() is indeed not defined, but according to other examples, I would think it should be.
Furthermore, setFooData() does exist on wrapper.instance().selector.props, and while let stub = sinon.stub(wrapper.instance().selector.props, 'setFooData'); avoids the error, when I inspect the object setFooData() =/= stub, and the function is not called as per the test.
When I use mount() instead,
let wrapper = mount(<Provider store={store}><Foo {...props}/></Provider>);
let componentDidMountSpy = sinon.spy(Foo.prototype, 'componentDidMount');
let componentWillReceivePropsSpy = sinon.spy(Foo.prototype, 'componentWillReceiveProps');
expect(componentDidMountSpy.called).to.be.true; //passes
expect(componentWillReceivePropsSpy.called).to.be.true; //passes
expect(stub.called).to.be.true; //fails
I receive a different error that appears related to the body of setFooData(), so setFooData() is called but the function is not actually stubbed to prevent its real body from being executed.
Thanks for any help to clarify my understanding.
I think you're taking the hardest path. You should test your component in isolation, not the connected one. If you test the connected component you're making an integration test and double testing that connect indeed works. That's already tested in react-redux for you.
Instead, test your action creators by themselves in unit tests.
Then, export your component as named export without connecting and use the default export for the connect version.
That way you can simply import the pure-React version and pass anything you want as props, in order to make easy assertions afterwards.
If you need to specifically test that something happens in those lifecycle methods, you can call those methods from the instance:
const fakeActionCreator = sinon.spy()
const subject = mount(<MyComponent doSomething={ fakeActionCreator } />)
subject.instance().componentDidMount()
assert.equal(fakeActionCreator.callCount, 1)
I want to write a unit test that check a stream has been copied on the disk :
The problem is CopyTo method is not virtual so I can't use
inputMemoryStreamMock.Verify(c => c.CopyTo(outputMemoryStreamMock.Object));
and I don't know how to mock a stream :-/
here is my test method :
[TestMethod]
public void Save_Stream_On_DestinationPath()
{
// Arrange
string fileName = "filename.pdf";
DateTime date = new DateTime(2013, 9, 27);
var serverConfigMock = new Mock<IServerConfigurationManager>();
serverConfigMock.Setup(config => config.ReportingBasePath).Returns(#"c:\reportsFolder");
var factoryReportFileResultMock = new Mock<IReportFileResultFactory>();
var timeManagementMock = new Mock<ITimeManagement>();
timeManagementMock.Setup(c => c.GetServerDate()).Returns(date);
var fileSystemMock = new Mock<IFileSystem>();
var fileInfoFactory = new Mock<IFileInfoFactory>();
var directoryInfoBaseMock = new Mock<DirectoryInfoBase>();
var inputMemoryStreamMock = new Mock<Stream>();
var outputMemoryStreamMock = new Mock<Stream>();
var reportFileHelper = new ReportFileHelper(serverConfigMock.Object, factoryReportFileResultMock.Object, fileSystemMock.Object);
inputMemoryStreamMock.Setup(c => c.CanRead).Returns(true);
outputMemoryStreamMock.Setup(c => c.CanWrite).Returns(true);
outputMemoryStreamMock.Setup(c => c.CanWrite).Returns(true);
fileSystemMock.Setup(c => c.FileInfo).Returns(fileInfoFactory.Object);
fileSystemMock.Setup(c => c.File.Create(It.IsAny<string>())).Returns(outputMemoryStreamMock.Object);
fileSystemMock.Setup(c => c.Directory.CreateDirectory(It.IsAny<string>())).Returns(directoryInfoBaseMock.Object);
// Act
reportFileHelper.Save(inputMemoryStreamMock.Object, fileName, timeManagementMock.Object);
// Assert
inputMemoryStreamMock.Verify(c => c.CopyTo(outputMemoryStreamMock.Object));
}
And here is the method to test :
public void Save(Stream portfolioReportFileInfoBase, string destinationName, ITimeManagement timeManagement)
{
string destinationPath = GetDestinationPath(timeManagement);
string destinationFileUri = Path.Combine(destinationPath, destinationName);
FileSystem.Directory.CreateDirectory(destinationPath);
using (var fileStream = FileSystem.File.Create(destinationFileUri))
{
portfolioReportFileInfoBase.CopyTo(fileStream);
}
}
Thank you
My take on a couple of things :
Readability
I'm not sure your test reads very nicely. Why do you declare a fileName variable as though it were important while you don't even assert on it ? Same goes for date. This clutters your test with unneeded detail. Inline values or Anonymous Variables allow for a better signal/noise ratio.
Then why do you set up CreateDirectory() to return something ? You never use that return value, do you ? I suggest you get rid of that and the directoryInfoBaseMock variable. Same with FileInfo and fileInfoFactory. Your test needs to contain the bare minimum to set up the objects you want to verify, and nothing more. If you need to build a deep, complex graph of objects just to test one simple thing, there's generally a problem somewhere.
Design
The second thing that raises an alarm is that Save() mixes multiple language levels. When you read it, it seems to be at the same time about :
Portfolios and reports
Time management
A lot of lower level filesystem stuff
This is often a sign that an object tries to handle too much, violating the Single Responsibility Principle.
What I would do is distribute these responsibilities across separate objects.
Why does Save() need to know about time management ? Sure, we use time management to compute the destination path, but wouldn't it be better aligned with the language level and responsibility level of a Save() method if we directly passed it the destination path instead ?
Why does Save() need to know about portfolios and reports ? Well, there's basically no reason. You could just rename portfolioReportFileInfoBase to... stream.
Save() and GetPath() could then be moved to a separate lower-level filesystem wrapper class (IFileSystem is a perfect candidate), removing the tight coupling between ReportFileHelper and the filesystem.
Don't try to test that your report is written to the disk using mocks. Do it with an integration test. Don't mock types you don't own. Use mocks only to test how your own classes talk to each other. Wrap external libraries/platforms into wrapper objects, and write integration tests at the boundaries of your application to verify that your wrappers play well with those external libraries/platforms.
You'll have to use an isolation framework like TypeMock Isolator or Microsoft Fakes to test this case if you're not willing to change the code of the Save method, since CopyTo can't be mocked by Moq.
You already encapsulated access to the filesystem behind IFileSystem; why not just add a method like CopyStreamToPath?
public void Save(Stream portfolioReportFileInfoBase, string destinationName, ITimeManagement timeManagement)
{
string destinationPath = GetDestinationPath(timeManagement);
string destinationFileUri = Path.Combine(destinationPath, destinationName);
FileSystem.Directory.CreateDirectory(destinationPath);
FileSystem.CopyStreamToPath(portfolioReportFileInfoBase, destinationFileUri);
}
and the test:
fileSystemMock.Verify(c => c.CopyStreamToPath(inputMemoryStreamMock.object, It.IsAny<string>()));
I need to find out the value passed into an indexer.
My code (c#) that I need to test is as follows:
string cacheKey = GetCacheKey(cacheKeyRequest);
string cachedValue = myCache[cacheKey] as string;
So, I need to be able to identify the value of the "cacheKey" that was passed into the indexer.
I have attempted this using a Mock of the cache object:
var cache = MockRepository.GenerateMock<WebDataCache>();
The idea being that after the code had executed, I would query the mock to identify the value that had been passed into the indexer:
var actualCacheKey = cache.GetArgumentsForCallsMadeOn(a => a["somevalue"], opt => opt.IgnoreArguments())[0][0].ToString();
This gives me a compilation error: Only assignment, call, increment, decrement, and new object expressions can be used as a statement.
I saw one suggestion to make this a function in the following way:
var actualCacheKey = cache.GetArgumentsForCallsMadeOn(a => a["somevalue"] = null, opt => opt.IgnoreArguments())[0][0].ToString();
This now compiles,but throws a run-time InvalidOperationException: No expectations were setup to be verified, ensure that the method call in the action is a virtual (C#) / overridable (VB.Net) method call.
Any suggestions? [Am using RhinoMocks.3.6.1]
Many thanks in advance
Griff
PS - I have previously posted this in http://groups.google.com/group/rhinomocks but after several days the view-count remains depressingly low.
The exception tells you exactly what is happening:
InvalidOperationException: No expectations were setup to be verified, ensure that the method call in the action is a virtual (C#) / overridable (VB.Net) method call.
Which means, in order for Rhino to properly work (or, in order for Castle to generate working proxies) your indexer has to be virtual. If you can't make it so, Rhino won't help you in this situation.
Once you make your indexer virtual, it is simple task:
var cache = MockRepository.GenerateMock<WebDataChache>();
cache.Expect(c => c["SomeKey"]).Returns("SomeValue");
// perform actual test
cache.VerifyAllExpectations();
This ensures that cache is accessed with ["SomeKey"]. If key value will be different, test will fail at VerifyAllExpectations line.
A second MSpec question from me in a day, this is a new record. I'm trying to get smart on MSpec very quickly and I've run into some old problems I've always had with MSpec.
Scenario: I have a repository that contains a bunch of cartoons. Right now I only need to filter this set on a single Name parameter, which is a string. As I'm told I'll need to filter this on more properties later on, I decide to create a class which takes in my ICartoonRepository via IoC, and contains a simple method that's called GetByName(string name).
You might argue this is overkill, but I'm trying to teach myself how to use MSpec and work in a more TDD manner.
So I create the following:
[Subject(typeof(CartoonViewModelBuilder))]
public class when_cartoon_repository_is_asked_to_get_by_id : specification_for_cartoon_viewmodel_builder
{
static string name;
static Cartoon the_cartoon;
static Cartoon result;
Establish context = () =>
{
name = "Taz";
the_cartoon = new Cartoon();
the_cartoon_repository.Stub(r => r.GetAll().Where(x=>x.Name == name).FirstOrDefault()).Return(the_cartoon);
};
Because of = () => result = subject.GetByName(name);
It should_return_cartoon = () => result.ShouldBeTheSameAs(the_cartoon);
}
This fails on the stub as the repository is empty. I have a couple other tests that pass fine (simply testing the GetAll(), etc). Do I need to add things to the repository to test it? This is where I'm stumped, please be gentle.
Also, if I'm writing the linq statement in the stub, it seems like I'm doing it twice, in the actual implementation and in the test. Is this the point? It doesn't feel right. Is there a better way I can write this test?
For clarity sake, here is the actual implementation (I'm omitting the interface and the class, which just has one property:
public class CartoonViewModelBuilder: ICartoonViewModelBuilder
{
readonly ICartoonRepository _cartoonRepository;
public CartoonQueryObject(ICartoonRepository cartoonRepository)
{
_cartoonRepository = cartoonRepository;
}
public IList<Cartoon> GetAllCartoons()
{
return _cartoonRepository.GetAll();
}
public Cartoon GetByName(string name)
{
return _cartoonRepository.GetAll().Where(x => x.Name == name).FirstOrDefault();
}
}
Edit 1: Based on the lack of responses, I should say that if I were using something like NUnit, I would be creating a method on the testing class that was like, "LoadDummyData" and threw data into the repository, then I'd do complex filtering or view model building and sort of manually checked what happened. This made large refactoring a chore. It seems like specs allows you to avoid that?
Edit 2: Here's my corrected test which now passes. Let me know if I'm doing it right, I think I am. Thanks again for the hand holding!
static string name;
static Cartoon the_cartoon;
static Cartoon result;
static IQueryable<Cartoon> the_cartoons;
Establish context = () =>
{
name = "Taz";
the_cartoon = new Cartoon {Name = name};
the_cartoons = new List<Cartoon> {the_cartoon, new Cartoon(), new Cartoon() }.AsQueryable();
the_cartoon_repository.Stub(r => r.GetAll()).Return(the_cartoons.ToList());
};
Because of = () => result = subject.GetByName(name);
It should_return_cartoon = () => result.ShouldBeTheSameAs(the_cartoon);
Edit 3: Gave you both points, but I can only award one best answer unfortunately.
The actual reason of this test failing is the way you're mocking your repository. I would be very surprised if method chains like r.GetAll().Where(x=>x.Name == name).FirstOrDefault() could be mocked so easily, as it uses LINQ extension methods and lambda clauses. The framework should really throw NotSupported exception or something to let you know that you can't mock LINQ queries as a whole.
To mock LINQ query result, you should provide properly prepared underlying data collection, which is the starting point of LINQ query. In your example you should mock just r.GetAll() to return a collection containing your element with proper name. The actual query will run on your "mocked" data and retrieve the object you expect.
This removes the need to duplicate your LINQ query in code and in test, what is strange, as you noted.
EDIT: Code in your edit is like I've suggested, technically OK.
Anyway, by now it's a bit overkill, as you've said. Your class under test doesn't do anything beside the call to the mocked repository, so the value of that test is rather small. But it may be a good start if you're going to have some more logic in GetByName method.
If you want to test your repository implementation, don't stub it! MSpec or not, I would add a list of known items to the repository and then issue the query with GetByName. Then assert that just the item you expect was returned. I would also use ShouldEqual as the repository might work with the items you add and return a different instance, though considered equal (aggregate IDs are equal).
I have the following test to verify that my repository is calling it's respective session (I've rewritten it to highlight the actual problem):
[Test]
public void Why_Does_This_Fail()
{
var objectUnderTest = new SomeGenericsProblem();
var fakeSession = MockRepository.GenerateMock<ISession>();
fakeSession.Expect(s => s.Query<SomeClass>());
objectUnderTest.NotWorking<SomeClass>();
fakeSession.AssertWasCalled(t => t.Query<SomeClass>());
}
but when I run the test I get this:
System.InvalidOperationException :
Invalid call, the last call has been
used or no call has been made (make
sure that you are calling a virtual
(C#) / Overridable (VB) method).(C#) / Overridable (VB) method).
Any ideas what I'm doing wrong here? The session that I'm mocking is an interface, so it has to be virtual/overridable.
I have a feeling it has something to do with the fact that my Query method is a generic, but I don't know any other way to express what I'm trying to test.
Also, If I remove the part that sets up the expectation (i.e. this line of code:)
fakeSession.Expect(s => s.Query<SomeClass>());
I get a different exception which is equally confusing to me:
System.InvalidOperationException : No
expectations were setup to be
verified, ensure that the method call
in the action is a virtual (C#) /
overridable (VB.Net) method calloverridable (VB.Net) method call
So I figured out what was wrong.
ISession comes from NHibernate, which I probably should have mentioned.
The reason why this is cruicialy important is because
session.Query<T>
(which is what I'm trying to mock), is an EXTENSION METHOD.
Rhino Mocks apparently does not have the capability of mocking extension methods, hence why it's giving me the weird error.
So hopefully I'll have saves someone else the time and agony I've gone through in trying to figure out why my test won't pass.
The only solution that I've read about for this is to actually change the design of the extension method (which I can't do because it's part of NHibernate), or to use a different mocking framework like TypeMock.
[Test]
public void Query_WhenCalled_CallsSessionQuery()
{
// arrange
var session = MockRepository.GenerateStub<ISession>();
var r = new Repository(session);
// act
r.Query<SomeClass>();
// assert
session.AssertWasCalled(s => s.Query<SomeClass>());
}