Unit Testing returns the value of a method called from another method

I have a method similar to this:

public List<MyClass> DoSomething(string Name, string Address, string Email, ref string ErrorMessage) { //Check for empty string parameters etc now go and get some data List<MyClass> Data = GetData(Name, Address, Email); /************************************************************* //How do I unit test that the data variable might be empty??? *************************************************************/ List<MyClass> FormattedData = FormatData(Data); return FormattedData; } 

I am just learning TDD / Unit Testing. My question is: how do I write a test to make sure that if GetData returns an empty list, I set ErrorMessage and then returned an empty list?

+4
source share
4 answers

During development, you should have left the entry point for testing as follows:

 public List<MyClass> DoSomething(string Name, string Address, string Email, ref string ErrorMessage, IDataProvider provider) { //Check for empty string parameters etc now go and get some data List<MyClass> Data = provider.GetData(Name, Address, Email); List<MyClass> FormattedData = FormatData(Data); return FormattedData; } 

And in unit testing you have to mock IDataProvider

He called Injection Dependency (DI) or Inversion Of Control (IOC)

general mocking library:

The list was taken from here.

Wikipedia articles:

Dependency Injection
Control inversion

NUnit Pseudocode:

 [Test] public void When_user_forgot_password_should_save_user() { // Arrange var errorMessage = string.Empty; var dataProvider = MockRepository.GenerateStub<IDataProvider>(); dataProvider.Stub(x => x.GetData("x", "y", "z", ref errorMessage )).Return(null); // Act var result DoSomething("x","y","z", ref errorMessage, dataProvider); // Assert //... } 
+2
source

Unit testing is not something that you add to the middle of existing methods, namely testing small units of code in isolation from the rest of the system so that you can be sure that the device behaves as it should.

So, you should write a second class, which should only answer to the fact that the class in which DoSomething lives (let this class be DaddyTests Daddy and the test class DaddyTests ) behaves as you expect. Then you can write a test method that calls DoSomething and ensures that ErrorMessage set appropriately (also ErrorMessage should be out param, not ref , if you don't pass the value to either).

To facilitate this test, you need to make sure that GetData not returning data. Trivially, you can do this by passing an empty dataset to a fake provider, but in more complex scenarios all classes may have to be swapped for fake / mock equivalents: using interfaces and dependency injection make this task very easy. (Normally, the provider is set during Daddy , not as a parameter in a DoSomething call.)

 public class Daddy { public List<MyClass> DoSomething(string Name, string Address, string Email, out string ErrorMessage, IDataProvider provider) { //Check for empty string parameters etc now go and get some data List<MyClass> Data = provider.GetData(Name, Address, Email); if (Data.Count == 0) { ErrorMessage = "Oh noes"; return Enumerable.Empty<MyClass>(); } List<MyClass> formattedData = FormatData(Data); return formattedData; } } [TestClass] public class DaddyTest { [TestMethod] public void DoSomethingHandlesEmptyDataSet() { // set-up Daddy daddy = new Daddy(); // test IList<MyClass> result = daddy.DoSomething("blah", "101 Dalmation Road", " bob@example.com ", out error, new FakeProvider(new Enumerable.Empty<AcmeData>())); // a class we've written to act in lieu of the real provider // validate Assert.NotNull(result); // most testing frameworks provides Assert functionality Assert.IsTrue(result.Count == 0); Assert.IsFalse(String.IsNullOrEmpty(error)); } } 

}

+3
source
 [TestMethod] public void MyDoSomethingTest() { string errorMessage = string.Empty; var actual = myClass.DoSomething(..., ref errorMessage) Assert.AreEqual("MyErrorMessage", errorMessage); Assert.AreEqual(0, FormattedData.Count); } 

I assume that if there is no datato format, the formatter will return an empty list.

Since you want to check the final result of the method, I would not try to figure out what was returned from the GetData function, since this is the return value of actaul that you want to check that it is an empty list and that FormatData doesn’t fail.

If you want to exit the function as quickly as possible, you can check if any of the parameters is null but empty, in which case it’s just

 errorMessage = "Empty parameters are not allowed"; return new List<MyClass>(); 
+1
source

IMO string

 List<MyClass> Data = GetData(Name, Address, Email); 

must be outside the class. With method signature changed to

 public List<MyClass> DoSomething(List<MyClass> data, ref string ErrorMessage) 

this method becomes much easier to test, since you can easily modify the input to check for all possible edge cases.

Another alternative is for the GetData method to be subject to a false dependency, which can then be tuned to return different results. So your class will look like this:

 class ThisClass { [Import] public IDataService DataService {get; set;} public List<MyClass> DoSomething(string Name, string Address, string Email, ref string ErrorMessage) { //Check for empty string parameters etc now go and get some data List<MyClass> Data = IDataService.GetData(Name, Address, Email); // using dependency List<MyClass> FormattedData = FormatData(Data); return FormattedData; } } 
+1
source

Source: https://habr.com/ru/post/1393140/


All Articles