單元測試系列
寫單元測試時,都需要隔離外部服務
把一些用到做法,記錄下來
寫單元測試的時候會用到隔離框架,隔離框架最常用的是NSubstitute,
是專門用Mock,stub...可以拿來做假物件,自訂回傳內容,做隔離測試
[TestFixture]
public class DemoTest
{
[Test]
public void CalculatorTestDemo()
{
//Create
var calculator = Substitute.For<ICalculator>();
//Set
calculator.Add(1, 2).Returns(3);
Assert.AreEqual(3, calculator.Add(1, 2));
}
}
public interface ICalculator
{
int Add(int num1, int num2);
string Mode { get; set; }
}
Substitute.For<ICalculator>();是專門在建立假物件
calculator.Add(1, 2).Returns(3);設定回傳值為3
上例就會依據設定的方法回傳3
[Test]
public void Test_GetStarted_ReceivedSpecificCall()
{
ICalculator calculator = Substitute.For<ICalculator>();
calculator.Add(1, 2);
calculator.Received().Add(1, 2);
calculator.DidNotReceive().Add(5, 7);
}
calculator.Received().Add(1, 2); 確認接收是否,有調用到此方法
calculator.DidNotReceive().Add(5, 7);確認接收是否,沒有調用到此方法
//example4
[Test]
public void Test_GetStarted_SetPropertyValue()
{
ICalculator calculator = Substitute.For<ICalculator>();
calculator.Mode.Returns("DESC");
Assert.AreEqual("DESC", calculator.Mode);
}
[Test]
public void Test_GetStarted_MultipleValues()
{
ICalculator calculator = Substitute.For<ICalculator>();
calculator.Mode.Returns("DESC", "DEC", "BEN");
Assert.AreEqual("DESC", calculator.Mode);
Assert.AreEqual("DEC", calculator.Mode);
Assert.AreEqual("BEN", calculator.Mode);
}
上方是用Return設定參數與多個參數值
//example 5
[Test]
public void Test_GetStarted_Matchrguments()
{
ICalculator calculator = Substitute.For<ICalculator>();
calculator.Add(10, -5);
calculator.Received().Add(10, Arg.Any<int>());
calculator.Received().Add(10, Arg.Is<int>(x=>x < 0));
}
任意(數字),型別=數字,Arg.Any<型別>()) EX:Arg.Any<int>()
指定條件Arg.Is<型別>(),小於0的條件方式 EX:Arg.Is<int>(x=>x < 0)
實例:
假設我要進行做會員登入成功和失敗,必須做隔離測試,如何做呢?
Model定義:
using System;
namespace Model
{
public class Member
{
public string UserId { get; set; }
public string Password { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
}
Define Repository Layer Interface and implement
using System;
using System.Collections.Generic;
using System.Text;
using Model;
namespace Repository.Interface
{
public interface IMemberRepository
{
Member GetByMember(string userid, string password);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using Model;
using Repository.Interface;
namespace Repository
{
public class MemberRepository : IMemberRepository
{
public List<Member> members = new List<Member>() {
new Member{ UserId = "test001",
Password = "test002",
Name ="Eddie",
Email = "aaa@gmail.com"}
};
public Member GetByMember(string userid, string password)
=> members.Where(m => m.UserId == userid && m.Password == password).FirstOrDefault();
}
}
Define Service Layer Interface and implement
using System;
using System.Collections.Generic;
using System.Text;
namespace Service.Interface
{
public interface IMemberService
{
bool Login(string userId, string password);
}
}
using Repository.Interface;
using Service.Interface;
using System;
namespace Service
{
public class MemberService : IMemberService
{
public readonly IMemberRepository _memberRepository;
public MemberService(IMemberRepository memberRepository)
{
_memberRepository = memberRepository;
}
public bool Login(string userid, string password)
{
var member = _memberRepository.GetByMember(userid, password);
if (member == null)
return false;
return true;
}
}
}
Create Unit Test Login Success and Login Fail
using NUnit.Framework;
using NSubstitute;
using Repository.Interface;
using Model;
using Service.Interface;
using Service;
namespace Tests
{
[TestFixture]
public class MemberTests
{
private IMemberRepository _memberRepository;
private IMemberService _memberService;
private Member _setReturnMember;
[SetUp]
public void Setup()
{
_memberRepository = Substitute.For<IMemberRepository>();
_memberService = new MemberService(_memberRepository);
_setReturnMember = new Member()
{
UserId = "test001",
Password = "test001",
Name = "test",
Email = "abc@gmail.com"
};
}
[Test]
public void Login_ReturnSuccess()
{
string userid = "test001";
string password = "test001";
_memberRepository.GetByMember(userid,password).Returns(_setReturnMember);
bool result = _memberService.Login(userid, password);
Assert.IsTrue(result);
}
[Test]
public void Login_ReturnFail()
{
string userid = "test001";
string password = "test002";
_memberRepository.GetByMember(userid, password).Returns(m => null);
bool result = _memberService.Login(userid, password);
Assert.IsFalse(result);
}
}
}
以上是使用的情境
元哥的筆記