0

Let's say I have a simple class called MyRequestHandler, and it has a method called ProcessRequest that simply takes a request object, maps it to a return object and returns that object. (This is obviously a very simple example of a much more complex method/test that I'm working on).

public class MyRequestHandler { private IMapper _mapper; public MyRequestHandler(IMapper maper) { _mapper = mapper; } public MyReturnObject ProcessRequest(MyRequestObject requestObject) { MyReturnObject returnObject = _mapper.Map<MyReturnObject>(requestObject); return returnObject; } } 

Now for unit testing (using Xunit), I want to test the ProcessRequest method, but obviously want to Moq the Map method, as such:

MyRequestObject requestObject = new RequestObject() { RequestInt = 1, RequestString = "Hello" }; MyReturnObject returnObject = new MyReturnObject() { MyInt = 1, MyString = "Hello" }; Mock<IMapper> mockMapper = new Mock<IMapper>(); mockMapper.Setup(m => m.Map<MyRequestObject>(requestObject)).Returns(returnObject); MyRequestHandler requestHandler = new MyRequestHandler(mockMapper.Object); MyReturnObject response = requestHandler.ProcessRequest(requestObject); Assert.Equal(returnObject.MyInt, response.MyInt); Assert.Equal(returnObject.MyString, response.MyString); 

The problem here is that Moq returns (and I guess it should be obvious that it is) a reference to returnObject, so my Asserts will always pass, even if my method were to change a value prior to returning the object. Now I could instantiate a new MyReturnObject in the Moq Setup/Return and compare the MyInt and MyString by the values I give to the new one, but what if it's a really complex object with 20 properties and lists of objects? Maybe I want to use AutoFixture to create the object being returned and use DeepEqual to compare them? Is this even possible? Am I looking at this wrong, or do I have to do some type of cloning in the Setup/Return to make this work?

2 Answers 2

1

I don't believe there is built in functionality to detect that method under test did not change object passed to it.

Options:

  • make sure that return objects are immutable - either by having them immutable to start with or by returning interface without "set" methods with an instance created via mocks
  • create separate instance for "expected" and "mocked" values and then compare property-by-property. There are plenty of helper libraries to do so (I like FluentAssertions).
  • just assert on individual properties instead of comparing objects - works fine for small number of fields.

If possible I'd prefer immutable objects - that prevent possibility of writing wrong code and thus decreases amount of testing needed.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! I'm debating between immutable and separate instances. With the separate instances I should be able to use the DeepEqual library to compare them. I just need to find the best way to make a clone of the object.
0

In this case you didn't receive a new data and can verify behavior

Internal state is not valuable in this case

var requestObject = new RequestObject(); var returnObject = new MyReturnObject(); ... var actual = requestHandler.ProcessRequest(requestObject); Assert.AreSame(returnObject, actual); mockMapper.Verify( instance => instance.Map<MyRequestObject>(requestObject), Times.Once); 

Some details

  1. we can't share write access with others, so i assume you have

    public class MyRequestObject { int RequestInt { get; private set; } string RequestString { get; private set; } }

otherwise you always should test for parameter mutation. You can imagine 10 participants called in depth and each of them should have such tests. These tests will weak against changes, they do nothing with new properties.

  1. It is better to have good coding convention and do codereview sometimes. In example someone can randomly remove private from property and it can't be catched with any tests.

  2. There are many good practices in example "write test before of code" and so on

2 Comments

I don't think this answer addresses the question at all - indeed the reference would be the same... But question is how to detect ProcessRequest changing returnObject.MyInt = 2 - it will pass verification just fine...
I guess we read "so my Asserts will always pass, even if my method were to change a value prior to returning the object" very differently (which is fine).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.