Ok, hela Microsoft Sverige sitter och sjunger julsånger på firmafesten men Micke har dragit på sig en fet Dagis-Ebola förkylning och ligger hemma och tycker synd om sig själv. Vad göra? Leka med NMock... Yepp! :-) Min syn på UnitTest är att hålla det så lång borta från integrationstest som det bara går. När Unittester börjar köra integrationstest i form av WebServiceanrop och ADO.net-fippel så händer två saker;

1. Hela tanken med "Unit" i UnitTest ballar ur...
2. Det kommer att sjukt lång tid att köra era 500 UnitTester (vilket kommer göra att de inte kommer att köras. alls..)

Ok, fine... Vi läser in oss på NMock via NMock tutorial sidan. Här börjar ett bra exempel med transferering av pengar mellan konton (och en bra instruktion om hur man kan generera ett NMock objekt för att ersätta det aktuella serviceanropet med en Mock implementation). Här skiver man att man har en "enkel" ASP.net sida uppbyggt enligt Model View Presenter modellen. Schysst!

Vyn ser ut såhär (Man är tydlig med att denna motsvaras av ASP.net sidan);
public interface ITransferFundsView
{
string FromAccount { get; }
string ToAccount { get; }
double Amount { get; }
}

Presentern såhär (Som en vanlig controller);
public class TransferFundsPresenter
{
private readonly ITransferFundsView view;
private readonly IAccountService accountService;

public TransferFundsPresenter(ITransferFundsView view, IAccountService accountService)
{
this.view = view;
this.accountService = accountService;
}
}

Vi sätter upp Testen såhär och skickar in vyn och modellen via constructorn till presentern.
[TestFixture]
public class TransferFundsPresenterTest
{
private Mockery mocks;
private ITransferFundsView mockView;
private IAccountService mockAccountService;
private TransferFundsPresenter presenter;

[SetUp]
public void SetUp()
{
mocks = new Mockery();
mockView = mocks.NewMock<ITransferFundsView>();
mockAccountService = mocks.NewMock<IAccountService>();
presenter = new TransferFundsPresenter(mockView, mockAccountService);
}

På detta sätt kan vi kicka igång aktuell UnitTest på detta sätt;
[Test]
public void ShouldQueryViewAndUseAccountServiceToTransferFunds()
{
Expect.Once.On(mockView).GetProperty("FromAccount").Will(Return.Value("1234"));
Expect.Once.On(mockView).GetProperty("ToAccount").Will(Return.Value("9876"));
Expect.Once.On(mockView).GetProperty("Amount").Will(Return.Value(200.00));
Expect.Once.On(mockAccountService).Method("TransferFunds").With("1234", "9876", 200.00);
presenter.TransferClicked();
mocks.VerifyAllExpectationsHaveBeenMet();
}

Ok, fine Service Mock Objektet är kanonbra men hur är det egentligen med vyn nu igen? Hur skulle en implementation i ASP.net se ut?
Såhär kanske? (Jag gjorde ett exempel med en enkel uppdatering av en Customer)

Aktuell Vy:
public interface ICustomerView
{
string FirstName
{get;set;}

string LastName
{get;set;}

string Status
{set;}
}

CodeBehind till CustomerWork.aspx
public partial class CustomerWork : Page, ICustomerView
{
public string FirstName
{
get { return FirstNameTextBox.Text; }
set { FirstNameTextBox.Text = value; }
}
public string LastName
{
get { return LastNameTextBox.Text; }
set { LastNameTextBox.Text = value; }
}
public string Status
{
set { StatusLabel.Text = value; }
}
private CustomerPresenter presenter;
protected void Page_Load(object sender, EventArgs e)
{
presenter = new CustomerPresenter(this as ICustomerView, new CustomerService());
}
protected void SaveButton_Click(object sender, EventArgs e)
{
presenter.CustomerSaveClicked();
}
}

Aktuell Presenter:
public class CustomerPresenter
{
private ICustomerView customerView;
private ICustomerService customerService;
public CustomerPresenter(ICustomerView customerView, ICustomerService customerService)
{
this.customerView = customerView;
this.customerService = customerService;
}
public void CustomerSaveClicked()
{
Customer customer = new Customer(customerView.FirstName, customerView.LastName);
string result = customerService.ProcessCustomer(customer);
customerView.Status = result;
}
}

Vi hookar upp presentern i Page_Load (vilket blir lite weird, men en nödlösning i ASP.net) enligt samma koncept som i NMock-exemplet och denna får kicka NMock implementationen av aktuell service. Vy interfacet implementerar vi för att kunna koppla av vyn och använda NMock för att ersätta presentationsskiktet i aktuell UnitTest. När någon klickar på knappen så delegerar vi jobbet till presentern som kickar på Modellen (i detta fallet tjänsten), helt fine. Det weirda blir vyn... Iallafall i ASP.net... Brukar ni skriva era ASP.net sidor på detta sätt? Och hur weird blir det inte om ni skall ha dynamiskt laddade UserControls till sidan... Enkelt? Har jag missat något? Hjäääääälp!!!

Mickes slutsats:
- Använd NMock till att koppla av integrationstest från unittest...
- Använd INTE NMock för att mocka presentationsgränssnitt, särskilt inte från ASP.net, det blir ALDRIG bra...

Det finns bra (?) verktyg för automatierade tester av vyer men det är knappast NMock och de brukar kosta en hel del deg och kräver en fabrik med människor iklädda vita rockar för att köra... Eller har jag missat något... :-)