Лучший ответ:
Гораздо логичнее и логичнее включить логическую схему в метод обхода, чем использовать две заглушки для одного и того же метода!Например, MyMethod считывает данные из трех разных файлов на диске, каждый из которых требует возврата различных фиктивных данных.Мы можем объехать System.IO.File.OpenRead и установить возвращаемое значение, проанализировав входные параметры OpenRead :
МЕТОД ТЕСТА:
[TestMethod]
[HostType("Moles")]
public void Test()
{
System.IO.Moles.MFile.OpenReadString = filePath => {
var mockStream = new System.IO.FileStream();
byte[] buffer;
switch (filePath)
{
case @"C:\DataFile.dat":
mockStream.Write(buffer, 0, 0); // Populate stream
break;
case @"C:\TextFile.txt":
mockStream.Write(buffer, 0, 0); // Populate stream
break;
case @"C:\LogFile.log":
mockStream.Write(buffer, 0, 0); // Populate stream
break;
}
return mockStream;
};
var target = new MyClass();
target.MyMethod();
}
Тип цели:
using System.IO;
public class MyClass
{
public void MyMethod()
{
var fileAData = File.OpenRead(@"C:\DataFile.dat");
var fileBData = File.OpenRead(@"C:\TextFile.txt");
var fileCData = File.OpenRead(@"C:\LogFile.log");
}
}
Прямой ответ на ваши вопросы:
Да для # 1 : создать один тип для каждого обхода, а затем использовать каждый для желаемого поведения.И yes to # 2 : воздействовать на один случай типа родинки или другой.Это требует добавления входных параметров метода или внедрения в конструктор класса.
Например, MyMethod считывает три файла данных с диска, и вам необходимо передать обратно три разных макета данных. MyMethod требует трех параметров - явно назойливое решение.(Обратите внимание, что входные параметры имеют тип FileInfo; потому что System.IO> Файл является статическим и не может быть создан: Например:
МЕТОД ТЕСТА:
[TestMethod]
[HostType("Moles")]
public void Test()
{
var fileInfoMoleA = new System.IO.Moles.MFileInfo();
fileInfoMoleA.OpenRead = () => { return new FileStream(); };
var fileInfoMoleB = new System.IO.Moles.MFileInfo();
fileInfoMoleB.OpenRead = () => { return new FileStream(); };
var fileInfoMoleC = new System.IO.Moles.MFileInfo();
fileInfoMoleC.OpenRead = () => { return new FileStream(); };
var target = new MyClass();
target.MyMethod(fileInfoMoleA, fileInfoMoleB, fileInfoMoleC);
}
TARGET TYPE:
using System.IO;
public class MyClass
{
// Input parameters are FileInfo type; because, System.IO.File
// is a static class, and can not be instantiated.
public void MyMethod(FileInfo fileInfoA, FileInfo fileInfoB, FileInfo fileInfoC)
{
var fileAData = fileInfoA.OpenRead();
var fileBData = fileInfoB.OpenRead();
var fileCData = fileInfoC.OpenRead();
}
}
ОБНОВЛЕНИЕ:
В ответ на комментарий @Chai можно создать общие методы в рамках тестового проекта, которыеможно ссылаться как делегат обхода. Например, вы можете захотеть написать общий метод, на который может ссылаться любой модульный тест, который устанавливает множество предварительно сконфигурированных сценариев. В следующем примере показано, как параметризованный метод может бытьиспользовать творческий подход - это всего лишь вызовы методов!
ТИПЫ ЦЕЛЕЙ:
namespace PexMoleDemo
{
public class MyClass
{
private MyMath _math;
public MyClass()
{
_math = new MyMath() { left = 1m, right = 2m };
}
public decimal GetResults()
{
return _math.Divide();
}
}
public class MyOtherClass
{
private MyMath _math;
public MyOtherClass()
{
_math = new MyMath() { left = 100m, right = 200m };
}
public decimal Divide()
{
return _math.Divide();
}
}
public class MyMath
{
public decimal left { get; set; }
public decimal right { get; set; }
public decimal Divide()
{
return left / right;
}
}
}
МЕТОДЫ ИСПЫТАНИЙ: наборы ArrangeScenarios ()обходные пути, включив параметр перечисления, что позволяет устанавливать одни и те же сценарии сухим способом на протяжении многих испытаний.
using System;
using Microsoft.Moles.Framework;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PexMoleDemo;
[assembly: MoledAssembly("PexMoleDemo")]
namespace TestProject1
{
[TestClass()]
public class ProgramTest
{
public enum Scenarios
{
DivideByZero,
MultiplyInsteadOfDivide
}
private void ArrangeScenario(Scenarios scenario)
{
switch (scenario)
{
case Scenarios.DivideByZero:
PexMoleDemo.Moles.MMyMath.AllInstances.rightGet =
instance => { return 0m; };
break;
case Scenarios.MultiplyInsteadOfDivide:
PexMoleDemo.Moles.MMyMath.AllInstances.Divide =
instance => { return instance.left * instance.right; };
break;
default:
throw new NotImplementedException("Invalid scenario.");
}
}
[TestMethod]
[HostType("Moles")]
[ExpectedException(typeof(DivideByZeroException))]
public void Test1()
{
ArrangeScenario(Scenarios.DivideByZero);
var target = new PexMoleDemo.MyClass();
var math = new PexMoleDemo.MyMath() { left = 1, right = 2 };
var left = math.left;
var right = math.right;
var actual = target.GetResults();
}
[TestMethod]
[HostType("Moles")]
public void Test2()
{
ArrangeScenario(Scenarios.MultiplyInsteadOfDivide);
// Perform some sort of test that determines if code breaks
// when values are multiplied instead of divided.
}
[TestMethod]
[HostType("Moles")]
[ExpectedException(typeof(DivideByZeroException))]
public void Test3()
{
ArrangeScenario(Scenarios.DivideByZero);
var target = new PexMoleDemo.MyOtherClass();
var math = new PexMoleDemo.MyMath() { left = 1, right = 2 };
var left = math.left;
var right = math.right;
var actual = target.Divide();
}
[TestMethod]
[HostType("Moles")]
public void Test4()
{
ArrangeScenario(Scenarios.MultiplyInsteadOfDivide);
// Perform some sort of test that determines if code breaks
// when values are multiplied instead of divided.
}
}
}