I need your help in order to find a way of verifying the value of nested objects passed as a parameter of the method under test invocation.
Assume this class:
public class AuditTrailValueObject
{
public ActionType Action { get; private set; }
public EntityType EntityType { get; private set; }
public long EntityId { get; private set; }
public DateTime StartTime { get; private set; }
public bool IsSuccess { get; private set; }
public string Remarks { get; private set; }
public AuditTrailValueObject(ActionType action, EntityType entityType, long entityId, DateTime startTime, bool isSuccess, string remarks = "")
{
Action = action;
EntityType = entityType;
EntityId = entityId;
StartTime = startTime;
IsSuccess = isSuccess;
Remarks = remarks;
}
}
And the following interface has this class as an injected dependency:
public interface IAuditTrailService
{
void WriteToAuditTrail(AuditTrailValueObject auditParamData);
}
Now I have the ScanService depending on the AuditTrailService (which implements IAuditTrailService):
public long CreateScanRequest(long projectId)
{
ScanRequestWriteModel scanRequest = _scanRequestWriteModelFactory.Create(projectDetails);
long scanRequestId = _scanRequestsWriteRepository.Insert(scanRequest);
_auditTrailService.WriteToAuditTrail(new AuditTrailValueObject(ActionType.Run, EntityType.SastScanRequest, scanRequestId, DateTime.UtcNow, true));
return scanRequestId;
}
The test I've written:
[TestMethod]
public void Scan_GivenProjectId_ShouldAuditSuccess()
{
//Given
var projectId = 100;
var scanService = CreateScanService();
...
A.CallTo(() => _scanRequestWriteModelFactory.Create(projectDetails)).Returns(new ScanRequestWriteModel());
A.CallTo(() => _scanRequestsWriteRepository.Insert(A<ScanRequestWriteModel>._)).Returns(1);
//When
var scanRequestId = scanService.CreateScanRequest(projectId);
//Then
A.CallTo(() => _auditTrailService.WriteToAuditTrail(
new AuditTrailValueObject(ActionType.Run, EntityType.SastScanRequest, scanRequestId, A<DateTime>._, true, A<string>._))).MustHaveHappened();
}
When running this test I'm getting:
System.InvalidCastException: Specified cast is not valid
How can I verify the value of a nested parameter in AuditTrailValueObject?
#tom redfern makes many good points, which you may want to address. But after rereading your code and comments, I think I an immediate way forward. Your code has at least one problem, and it may have another.
Let's look at
A.CallTo(() => _auditTrailService.WriteToAuditTrail(
new AuditTrailValueObject(ActionType.Run,
EntityType.SastScanRequest,
scanRequestId,
A<DateTime>._,
true
A<string>._)))
.MustHaveHappened();
The _ constructs are being used here inside the AuditTrailValueObject constructor, and they are not valid there. They'll result in default values being assigned to the AuditTrailValueObject, (DateTime.MinValue and null, I think), and are almost not what you want. if you extract the new out to the previous line, you'll see FakeItEasy throw an error when _ is used. I think that it should do a better job of helping you find the problem in your code, but I'm not sure it's possible. I've created FakeItEasy Issue 1177 -
Argument constraint That, when nested deeper in A.CallTo, misreports what's being matched to help FakeItEasy improve.
Related to this is how FakeItEasy matches objects. When provided with a value to compare, (the result of new AuditTrailValueObject(…)) FakeItEasy will use Equals to compare the object against the received parameter. Unless your AuditTrailValueObject has a good Equals, this will fail.
If you want to keep using AuditTrailValueObject and don't want to provide an Equals (that would ignore the startTime and the remarks), there are ways forward.
First, you could use That.Matches, like so:
A.CallTo(() => _auditTrailService.WriteToAuditTrail(A<AuditTrailValueObject>.That.Matches(
a => a.Action == ActionType.Run &&
a.EntityType == EntityType.SastScanRequest &&
a.EntityId == scanRequestId &&
a.IsSuccess)))
.MustHaveHappened();
Some people aren't wild about complex constraints in the Matches, so an alternative is to capture the AuditTrailValueObject and interrogate it later, as Alex James Brown has described in his answer to Why can't I capture a FakeItEasy expectation in a variable?.
Your problem is a symptom of a larger problem: you are trying to do too much with one test.
Because you're newing-up an instance of AuditTrailValueObject in your WriteToAuditTrail() method, you will have no means of accessing this object instance as it is created within the method scope and is therefore immune to inspection.
However, it appears that the only reason you wish to access this object in the first place is so that you can verify that the values being set within it are correct.
Of these values, only one (as far as your code sample allows us to know) is set from within the calling method. This is the return value from the call made to _scanRequestsWriteRepository.Insert(), which should be the subject of its own unit test where you can verify correct behaviour independently of where it is being used.
Writing this unit test (on the _scanRequestsWriteRepository.Insert() method) will actually address the underlying cause of your problem (that you are doing too much with a single test). Your immediate problem, however, still needs to be addressed. The simplest way of doing this is to remove the AuditTrailValueObject class entirely, and just pass your arguments directly to the call to WriteToAuditTrail().
If I'll remove AuditTrailValueObject where the place should I verify
what params are being passed to the auditTrailService? What I mean is
that also if I've tested the auditTrailService I need to know that
scan service call if with the right parameters (for example: with
ActionType.Run and not with ActionType.Update).
To verify that the correct parameters have been passed to the call to WriteToAuditTrail() you can inject a fake of IAuditTrailService and verify your call has happened:
A.CallTo(
() => _auditTrailService.WriteToAuditTrail(
ActionType.Run,
EntityType.SastScanRequest,
scanRequestId,
myDateTime,
true,
myString)
).MustHaveHappened();
Related
I'm using the MockingContainer<T> to automatically set up my dependencies. How do I assert that a property on one of those dependencies gets set?
[SetUp]
public void SetUp()
{
//arrange
_baseUrl = "http://baseUrl";
_container = new MockingContainer<ApiInteractionService>();
_container.Arrange<IConfigService>(m => m.BaseUrl).Returns(_baseUrl);
_uut = _container.Instance;
}
The following fails with 0 calls, which makes sense since I believe it's looking at the Getter, not the Setter. So how do I assert that the Setter was called by the unit under test?
[Test]
public void BaseUrlSet()
{
//act
var _ = _uut.MakeRequest((InitialRequest) Arg.AnyObject);
//assert
_container.Assert<IRestService>(m => m.BaseUrl, Occurs.Once());
}
Per the documentation (located at JustMock Docs for anyone who isn't familiar but wishes to try assisting) it appears I should be using Mock.ArrangeSet(lambda), however I cannot seem to figure out how to get that syntax to work in relation to MockingContainer<T>.
If worse comes to worse, I can just NOT use MockingContainer<T>, but I'd prefer to not have to refactor my test suite just to accommodate one specific unit test.
Not that it's really relevant to the question, but in the off chance anyone needs it, here is a stub of ApiInteractionService
public ApiInteractionService(IRestService restService, IConfigService configService)
{
_restService = restService;
_restService.BaseUrl = configService.BaseUrl;
}
public string MakeRequest(InitialRequest initialRequest)
{
return _restService.Post(initialRequest);
}
Why not simply assert that BaseUrl has the correct value at the end of the test?
var baseUrl = _container.Get<IRestService>().BaseUrl;
Assert.AreEqual(baseUrl, _baseUrl);
As suggested in the comments, _container.Assert<IRestService>(m => m.BaseUrl == _baseUrl) will not work. MockingContainer<T>.Assert asserts an expectation, it's not just asserting truth like regular asserts. The correct syntax would have been:
_container.AssertSet<IRestService>(restService => restService.BaseUrl = _baseUrl, Occurs.Once());
but, oddly, there is no AssertSet method on the container.
I am using Moq in my unit test project. Most unit test examples I've seen online end with someMock.VerifyAll(); I wonder if it is OK to assert after VerifyAll(). So for example,
//Arrange
var student = new Student{Id = 0, Name="John Doe", IsRegistered = false};
var studentRepository = new Mock<IStudentRepository>();
var studentService= new StudentService(studentRepository.Object);
//Act
studentService.Register(student); //<-- student.IsRegistered = true now.
//Verify and assert
studentRepository.VerifyAll();
Assert.IsTrue(student.IsRegistered);
Any thought? Thank you.
No you should not use both together in most cases(there are always exceptions). The reason for that is you should be testing only one thing in your test for maintainability, readability and few other reasons. So it should be either Verify(VerifyAll) or Assert in your test and you name your tests accordingly.
Look at Roy Osherove's article about it:
http://osherove.com/blog/2005/4/3/a-unit-test-should-test-only-one-thing.html
VerifyAll is used to make sure certain methods are called and how many times. You use mocks for that.
Assert is used for verifying the result returned from the method you are testing. You use Stubs for that.
Martin fowler has a great article explaining the difference between mocks and stubs. If you understand it you will know the difference better.
http://martinfowler.com/articles/mocksArentStubs.html
UPDATE: example of mock vs stub using Moq as requested in the comment below. I have used Verify but you can use VerifyAll as well.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
...
[TestClass]
public class UnitTest1
{
/// <summary>
/// Test using Mock to Verify that GetNameWithPrefix method calls
/// Repository GetName method once when Id is greater than Zero
/// </summary>
[TestMethod]
public void GetNameWithPrefix_IdIsTwelve_GetNameCalledOnce()
{
// Arrange
var mockEntityRepository = new Mock<IEntityRepository>();
mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
var entity = new EntityClass(mockEntityRepository.Object);
// Act
var name = entity.GetNameWithPrefix(12);
// Assert
mockEntityRepository.Verify(
m => m.GetName(It.IsAny<int>()), Times.Once);
}
/// <summary>
/// Test using Mock to Verify that GetNameWithPrefix method
/// doesn't calls Repository GetName method when Id is Zero
/// </summary>
[TestMethod]
public void GetNameWithPrefix_IdIsZero_GetNameNeverCalled()
{
// Arrange
var mockEntityRepository = new Mock<IEntityRepository>();
mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
var entity = new EntityClass(mockEntityRepository.Object);
// Act
var name = entity.GetNameWithPrefix(0);
// Assert
mockEntityRepository.Verify(
m => m.GetName(It.IsAny<int>()), Times.Never);
}
/// <summary>
/// Test using Stub to Verify that GetNameWithPrefix method
/// returns Name with a Prefix
/// </summary>
[TestMethod]
public void GetNameWithPrefix_IdIsTwelve_ReturnsNameWithPrefix()
{
// Arrange
var stubEntityRepository = new Mock<IEntityRepository>();
stubEntityRepository.Setup(m => m.GetName(It.IsAny<int>()))
.Returns("Stub");
const string EXPECTED_NAME_WITH_PREFIX = "Mr. Stub";
var entity = new EntityClass(stubEntityRepository.Object);
// Act
var name = entity.GetNameWithPrefix(12);
// Assert
Assert.AreEqual(EXPECTED_NAME_WITH_PREFIX, name);
}
}
public class EntityClass
{
private IEntityRepository _entityRepository;
public EntityClass(IEntityRepository entityRepository)
{
this._entityRepository = entityRepository;
}
public string Name { get; set; }
public string GetNameWithPrefix(int id)
{
string name = string.Empty;
if (id > 0)
{
name = this._entityRepository.GetName(id);
}
return "Mr. " + name;
}
}
public interface IEntityRepository
{
string GetName(int id);
}
public class EntityRepository:IEntityRepository
{
public string GetName(int id)
{
// Code to connect to DB and get name based on Id
return "NameFromDb";
}
}
Yes you should call the assert.
VerifyAll() will assert that all SetUp() calls were actually called.
VerifyAll() will not confirm that your student object is registered. Because there are no SetUp() calls in your test case, I think VerifyAll() isn't verifying anything.
I would absolutely expect to see Verify and Assert used side-by-side within a unit test. Asserts are used to validate that properties of your system under test have been set correctly, whereas Verify is used to ensure that any dependencies that your system under test takes in have been called correctly. When using Moq I tend to err on the side of explicitly verifying a setup rather than using the VerifyAll catch-all. That way you can make the intent of the test much clearer.
I'm assuming in the code above that your call to the student repository returns a boolean to state that the student is registered? And you then set that value on the student object? In that case, there is a valuable setup that needs to be added, in which you are effectively saying that when the student repository method is called, it will return true. Then you Assert that student.IsRegistered is true to ensure that you have set the property correctly from the repository return value and you Verify that the repository method is called with the inputs that you are expecting.
There's nothing intrinsically wrong with both asserting and verifying in a mocking test, though assertions that depend on the actual methods being called are likely to fail, because the mock methods do not have the same effects as the real methods.
In your example it is probably fine, as only the repository is mocked, and the change of the student state is presumably done in the service.
Whether both verify and assert should be done in the same test is to a degree a matter of taste. Really the verify is checking that the proper calls to the repository are made, and the assert is checking that the proper change to the entity is made. As these are separate concerns, I'd put them in separate tests, but that may just be me.
In an earlier question I asked about Autofixture's CreateProxy method, a potential bug was identified.
I don't think this failing test is as a result of that, but rather my continued confusion about how the Likeness.Without(...).CreateProxy() syntax works. Consider the following failing test in which I make the original test ever so slightly more complex by creating a new instance of the object, considering its creation to be the SUT:
[Fact]
public void Equality_Behaves_As_Expected()
{
// arrange: intent -> use the fixture-created Band as Object Mother
var template = new Fixture().Create<Band>();
// act: intent -> instantiated Band *is* the SUT
var createdBand = new Band {Brass = template.Brass,
Strings = template.Brass};
// intent -> specify that .Brass should not be considered in comparison
var likeness = template.AsSource().OfLikeness<Band>().
Without(x => x.Brass).CreateProxy(); // Ignore .Brass property
// per [https://stackoverflow.com/a/15476108/533958] explicity assign
// properties to likeness
likeness.Strings = template.Strings;
likeness.Brass = "foo"; // should be ignored
// assert: intent -> check equality between created Band & template Band
// to include all members not excluded in likeness definition
likeness.Should().Be(createdBand); // Fails
likeness.ShouldBeEquivalentTo(createdBand); // Fails
Assert.True(likeness.Equals(createdBand)); // Fails
}
Here's the Band:
public class Band
{
public string Strings { get; set; }
public string Brass { get; set; }
}
My earlier question wasn't sufficiently complex to help me understand what the Source of the Likeness should be in general.
Should the source be the output of the SUT, in which case it would be compared to the template instance created by AutoFixture?
Or should the source be the template instance created by AutoFixture, in which case it would be compared to the output of the SUT?
EDIT: Corrected an error in the test
I realized that I had incorrectly assigned the template.Brass property to both the Brass and the Strings property of the new Band instance. The updated test reflects the correction with var createdBand = new Band {Brass = template.Brass, Strings = template.Strings} and all six assertions pass now.
[Fact]
public void Equality_Behaves_As_Expected()
{
// arrange: intent -> use the fixture-created Band as Object Mother
var template = new Fixture().Create<Band>();
// act: intent -> instantiated Band *is* the SUT
var createdBand = new Band {Brass = template.Brass, Strings = template.Strings};
// likeness of created
var createdLikeness = createdBand.AsSource().OfLikeness<Band>().
Without(x => x.Brass).CreateProxy(); // .Brass should not be considered in comparison
// https://stackoverflow.com/a/15476108/533958 (explicity assign properties to likeness)
createdLikeness.Strings = createdBand.Strings;
createdLikeness.Brass = "foo"; // should be ignored
// likeness of template
var templateLikeness = template.AsSource().OfLikeness<Band>()
.Without(x => x.Brass)
.CreateProxy();
templateLikeness.Strings = template.Strings;
templateLikeness.Brass = "foo";
// assert: intent -> compare created Band to template Band
createdLikeness.Should().Be(template);
createdLikeness.ShouldBeEquivalentTo(template);
Assert.True(createdLikeness.Equals(template));
templateLikeness.Should().Be(createdBand);
templateLikeness.ShouldBeEquivalentTo(createdBand);
Assert.True(templateLikeness.Equals(createdBand));
}
What you mean is:
likeness.Should().BeAssignableTo<Band>(); // Returns true.
In the example provided, the proxy generated from Likeness is a type deriving from Band, overriding Equals using the Semantic Comparison algorithm.
Using Reflection that is:
createdBand.GetType().IsAssignableFrom(likeness.GetType()) // Returns true.
Update:
The createBand and template instances are not affected by the CreateProxy method. Why they should?
With Likeness CreateProxy you basically create a Custom Equality Assertion that allows you to do:
Assert.True(likeness.Equals(createdBand)); // Passed.
Without it, the original Equality Assertion would fail:
Assert.True(template.Equals(createdBand)); // Failed.
However, the following will also fail:
Assert.True(likeness.Equals(template));
It fails because the Strings value is the one from the createdBand instance.
This behavior is expected, and you can verify it using Likeness directly:
createdBand.AsSource().OfLikeness<Band>()
.Without(x => x.Brass).ShouldEqual(template);
Output:
The provided value `Band` did not match the expected value `Band`. The following members did not match:
- Strings.
I'm sure I missing something simple here but I can't figure out why my NUnit object comparison test continues to fail.
I have a simple object:
public virtual int Id { get; private set; }
public virtual string Description { get; set; }
public virtual string Address { get; set; }
public virtual string Ports { get; set; }
public virtual string Password { get; set; }
public virtual ServerGroup ServerGroup { get; set; }
I am persisting an instance of this object to my database and then fetching it out using NHibernate. My NUnit unit test compares the object saved to the object retrieved and compares them. I understand that AreSame() would fail as they are not the same reference to an object but I would expect that AreEqual() pass.
If I debug the test I can see that both objects appear to have the same values in these properties my test still fails. Can someone tell me why?
Thanks!
You have to override Equals() method on your class. Otherwise NUnit will use the base implementation, which compares references (which is certainly not what you are after here)
As suggested you need to override Equals. You do need to be aware of the side effects.
You should also override GetHashCode or you could end up with objects where .Equals will be true, but using your Id class as the key in a Dictionary the hash would not match resulting in multiple entries with "Equal" Ids.
Also, you would need to override the == and != operators to maintain consistent behavior.
Imagine the confusion if .Equals were true but == were false.
You do need to override Equals as Grzenio suggests, but watch out for a subtle source of confusion that can occur with NHibernate. Specifically, when lazy loading is enabled, a type comparison test can fail. To illustrate, here is a piece of a well written Equals method:
// override object.Equals
public override bool Equals(object obj)
{
//
// See the full list of guidelines at
// http://go.microsoft.com/fwlink/?LinkID=85237
// and also the guidance for operator== at
// http://go.microsoft.com/fwlink/?LinkId=85238
//
if (GetType() != obj.GetType())
{
return false;
}
....
}
But when lazy loading is enabled, the way NHib works is to generate a proxy of the actual object (thereby deferring unnecessary database hits). If an equality check is made between one object that has been 'proxified' by NHib and another that hasn't been, it will fail because of the mismatch in Types. The solution (courtesy of the S#arp Architecture project, is to modify the type test to be something like this:
public override bool Equals(object obj) {
...
if (GetType() != obj.GetTypeUnproxied())
{
return false;
}
...
}
protected virtual Type GetTypeUnproxied() { return GetType(); }
This effectively returns the type of the underlying object in all cases, even when the compareTo object is a NHib proxy.
An Equals method can be as tricky as it is important to get just right, so ideally you can factor that into some sort of Layer Supertype (Fowler). Lots of open source projects, including the S#arp one I mentioned earlier, provide examples of how to do this.
HTH,
Berryl
I've isolated the behaviour into the following test case. I'd be grateful to anyone who can tell me how to expect/verify a property set for a List<T> property - it appears there's something going on inside It.Is<T>(predicate) that isn't making a whole lot of sense to me right now. Sample code will run as a console app from VS2008 - you'll need to add a reference to Moq 2.6 (I'm on 2.6.1014.1) - please try uncommenting the different ExpectSet statements to see what's happening...
using System;
using Moq;
using System.Collections.Generic;
namespace MoqDemo {
public interface IView {
List<string> Names { get; set; }
}
public class Controller {
private IView view;
public Controller(IView view) {
this.view = view;
}
public void PopulateView() {
List<string> names = new List<string>() { "Hugh", "Pugh", "Barney McGrew" };
view.Names = names;
}
public class MyApp {
public static void Main() {
Mock<IView> mockView = new Mock<IView>();
// This works - and the expectation is verifiable.
mockView.ExpectSet(mv => mv.Names);
// None of the following can be verified.
// mockView.ExpectSet(mv => mv.Names, It.Is<Object>(o => o != null));
// mockView.ExpectSet(mv => mv.Names, It.Is<List<string>>(names => names.Count == 3));
// mockView.ExpectSet(mv => mv.Names, It.IsAny<IList<String>>());
Controller controller = new Controller(mockView.Object);
controller.PopulateView();
try {
mockView.VerifyAll();
Console.WriteLine("Verified OK!");
} catch (MockException ex) {
Console.WriteLine("Verification failed!");
Console.WriteLine(ex.Message);
}
Console.ReadKey(false);
}
}
}
}
I'm not using the very latest version of Moq, so I don't have an overload of ExpectSet that takes two parameters, but I've had some success with this pattern:
mockView.ExpectSet(mv => mv.Names).Callback(n => Assert.That(n != null));
The Assert (from NUnit) call in the callback will throw an exception if the value assigned to .Names doesn't match the predicate. It does make it hard to trace when a test fails, though. I agree that the ability to pass an It.Is or It.IsAny as the second parameter would be handy.
The second parameter of ExpectSet() is the value you're expecting. You can't use It.Is<T> in this case as there's no overload that takes a predicate - though it would be nice ;) Here's a (simplified) excerpt from your sample, illustrating the use of a value:
var mockView = new Mock<IView>();
var list = new List<string> { "Hugh", "Pugh", "Barney McGrew" };
mockView.ExpectSet(mv => mv.Names, list);
mockView.Object.Names = list;
Hope that helps.
Edit: fixed typo.
BTW, It.Is is not supported on ExpectSet. Your code compiles just because they are regular method invocations when used as values (as opposed to expressions), whereas when used in an Expect expression they are pre-processed by Moq and given specific meaning (rather than the null/default value that all It.Is members actually return).
You could use the stub behavior on the given property (mockView.Stub(mv => mv.Names)) and later assert directly for its value after execution.
Moq doesn't provide an overload receiving It.IsAny as it's effectively the same as calling ExpectSet without passing an expected value ;)