For a dotnet developer who plans unit testing, the question rarely arises as to what is meant by this notorious “unit”: in the overwhelming number of cases, a unit is a class, and thus any test that uses two or more unit classes is not - this is already an integration test. Here, of course, we are talking about our classes, since binding to the framework or third-party libraries is quite a normal thing, and does not need testing (although how to say ...). public class Worker
{
private List <int> workHours {get; set; }
public int GetTotalHoursWorked () {return workHours.Sum (); }
}
public class Payroll
{
public int CalculatePay (Worker worker)
{
// pay everyone 10 dollars an hour (I am evil)
return worker.GetTotalHoursWorked () * 10;
}
}
Payroll class, but in order for it to be a real unit test, we need to isolate the dependent Person class so that, for example, the GetTotalHoursWorked() function is not called at all . How to do it? Very simple: First, we create a Payroll as usual, but instead of Person we create a mock object:Worker w = Isolate.Fake.Instance <Worker> (); Payroll p = new Payroll ();
Worker will not be affected. To do this, you need to change the GetTotalHoursWorked() call. Here is how it is done:Isolate.WhenCalled (() => w.GetTotalHoursWorked ()). WillReturn (40);
Person.GetTotalHoursWorked() number 40 will be Person.GetTotalHoursWorked() returned. If you do not believe it, set a breakpoint on the function and you will see that no one is included in the testing.int result = p. CalculatePay (w);
workHours not initialize workHours — the value is null . However, we have a very realistic result - 400. Moreover, we can even check that the GetTotalHoursWorked() method was actually called (the fact that the changed method was called does not matter). This is the last phase of AAA, namely Assert. We look:Assert.AreEqual (400, result); Isolate.Verify.WasCalledWithAnyArguments (() => w.GetTotalHoursWorked ());
[Test]
public void TestPayroll ()
{
// Arrange
Payroll p = new Payroll ();
Worker w = Isolate.Fake.Instance <Worker> ();
Isolate.WhenCalled (() => w.GetTotalHoursWorked ()). WillReturn (40);
// Act
int result = p. CalculatePay (w);
// Assert
Assert.AreEqual (400, result);
Isolate.Verify.WasCalledWithAnyArguments (() => w.GetTotalHoursWorked ());
}
Payroll.CalculatePay() method, replacing the Person parameter with a certain similarity that behaved predictably and did not affect the actual properties and methods of the class.Worker.GetTotalHoursWorked() method is in a different assembly, and is marked as internal : public class Worker
{
private List <int> workHours {get; set; }
internal int GetTotalHoursWorked () {return workHours.Sum (); }
}
GetTotalHoursWorked() no longer have access to it:// will not work Isolate.WhenCalled (() => w.GetTotalHoursWorked ()). WillReturn (40); // this too Isolate.Verify.WasCalledWithAnyArguments (() => w.GetTotalHoursWorked ());
Isolator.NonPublic we can set the method by name:Isolate.NonPublic.WhenCalled (w, "GetTotalHoursWorked"). WillReturn (40); ... Isolate.Verify.NonPublic.WasCalled (w, "GetTotalHoursWorked");
operator this[] ). Well, checks for calls can be done accordingly.new operator, TypeMock can also work with static objects. For example, to fake a static constructor, we simply call Isolate.Fake.StaticConstructor(typeof (T)); , and then use TypeMock as before. The same is done with static methods. public class Dog
{
public Dog () {}
public string MakeSound ()
{
return "Woof";
}
}
public class Duck
{
public string MakeSound ()
{
return "Quack";
}
}
[TestFixture, Isolated]
public class Tests
{
[Test]
public void Test ()
{
// fake a dog
Dog dog = Isolate.Fake.Instance <Dog> ();
Duck duck = new Duck ();
// replace calls on dog with calls on duck
Isolate.Swap.CallsOn (dog) .WithCallsTo (duck);
// get a dog to quack
string sound = dog.MakeSound ();
// did it?
Assert.AreEqual ("Quack", sound);
Isolate.Verify.WasCalledWithAnyArguments (() => dog.MakeSound ());
}
}
Test attribute, the Isolated attribute must be used either at the method level or at the class level — this attribute allows you to clear the context of the used mock objects.Source: https://habr.com/ru/post/56917/
All Articles