I was following a book Art of Unit Testing, This book says that You must not have any logic in Your asserts as this reduces readability of test, or I may be testing too many things at a time. Suppose there is a method with signature as below:
public int DoSomething(int variable1, out string variable2, out float variable3)
{
...
}
How should I test this method, as I have to assert on return value, variable2, variable3 ???
Sample Test method that tests all of these three concerns:
public void DosSomethingTest(){
//add code for arrange
int expectedvalue=12;
string expectedVariable1="I am expected";
string expectedVariable3=15.9;
string actualVariable1, actualVariable3;
var sut=new Foo();
int actualValue=sut.DoSomething(15, out actualVariable1, out actualVariable3);
//this is where I am testing 3 concerns in one test. Is there a better way?
if(actualValue==expectedvalue){
if(expectedVariable1==actualVariable1){
if(expectedVariable3!=actualVariable3){
Assert.Fail("Unexpected variable2 returned");//pseudo code
}
}
else{
Assert.Fail("Unexpected variable1 returned");//pseudo code
}
}
else{
Assert.Fail("Unexpected Value returned");//pseudo code
}
}
Approach 2
Seperate Test methods that tests concerns separately:
public void DosSomething_Passing15_Returns12Test(){
//add code for arrange
int expectedvalue=12;
string expectedVariable1="I am expected";
string expectedVariable3=15.9;
string actualVariable1, actualVariable3;
var sut=new Foo();
int actualValue=sut.DoSomething(15, out actualVariable1, out actualVariable3);
Assert.IsTrue(actualValue, expectedvalue);
}
public void DosSomething_Passing15_ReturnsExpectedVariable1Test(){
//add code for arrange
int expectedvalue=12;
string expectedVariable1="I am expected";
string expectedVariable3=15.9;
string actualVariable1, actualVariable3;
var sut=new Foo();
int actualValue=sut.DoSomething(15, out actualVariable1, out actualVariable3);
Assert.IsTrue(actualVariable1, expectedVariable1);
}
public void DosSomething_Passing15_ReturnsExpectedVariable2Test(){
//add code for arrange
int expectedvalue=12;
string expectedVariable1="I am expected";
string expectedVariable3=15.9;
string actualVariable1, actualVariable3;
var sut=new Foo();
int actualValue=sut.DoSomething(15, out actualVariable1, out actualVariable3);
Assert.IsTrue(actualVariable3, expectedVariable3);
}
Isn't approach 2 adhering to "Tests should not test more than one concern"?
Conclusion
If redesigning of SUT is possible:
- There should ideally be no out parameter instead an aggregate class should be evaluated in Asserts.
- If there are unrelated out parameters then SUT method should be refactored into multiple methods, then those new methods should have their own Test methods and they will then test only one concern.
If redesigning of SUT is not possible then as per the answer there will be three Asserts