2013-02-12 34 views
2

隨着JustMock我可以模擬的DataContext表與Linq中的列表,輕鬆這樣的SQL,其中一個IEnumerable正在各的DataContext的表的地方通過ReturnsCollection()讓我在假數據插入:FakeItEasy中JustMock的ReturnsCollection()的等價物?

[TestMethod] 
public void ShouldGetManagersByHireDate() 
{ 
    var context = Mock.Create<MyDataContext>(); 
    Mock.Arrange(()=> context.Employees).ReturnsCollection(GetFakeEmployees()); 
    Mock.Arrange(() => context.Managers).ReturnsCollection(GetFakeManagers()); 

    var repository = new EmployeeRepository(context); 
    var managers = repository.GetManagersByHireDate(new DateTime(2002, 1, 1), DateTime.Now); 

    Assert.AreEqual(1, managers.Count()); 
    Assert.AreEqual(1, managers.FirstOrDefault().ID); 
} 

private IEnumerable<Employee> GetFakeEmployees() 
{ 
    return new List<Employee> { 
     new Employee { ID = 1, HireDate = new DateTime(2004, 12, 1) }, 
     new Employee { ID = 2, HireDate = new DateTime(2006, 7, 1) }, 
     new Employee { ID = 3, HireDate = new DateTime(2009, 3, 1) } 
    }; 
} 

private IEnumerable<Manager> GetFakeManagers() 
{ 
    return new List<Manager> { 
     new Manager { ID = 1 } 
    }; 
} 

而且這將是測試方法:

public IQueryable<Employee> GetManagersByHireDate(DateTime start, DateTime end) 
{ 
    return from e in context.Employees 
      join m in context.Managers on e.ID equals m.ID 
      where e.HireDate >= start && e.HireDate <= end 
      select e; 
} 

我尋找執行相同的魔術讓我代替Table<T>使用IEnumerable<T>測試LINQ的宗旨,以SQL,最好在FakeItEasy的某種方式。

+0

我沒有在你的例子中的任何地方看到'表'? – 2013-02-21 12:07:43

+0

@AdamRalph JustMock的ReturnsCollection允許您爲給定的linq查詢http://goo.gl/VBuPP返回一個可枚舉值。在這種情況下,測試人員不需要返回表中的排列方法http://goo.gl/45HC7 – cecilphillip 2013-02-21 19:52:59

+0

此外,FakeItEasy使用Castle的DynamicProxy,它不能攔截非虛擬方法 – cecilphillip 2013-02-22 20:26:56

回答

2

Linq to SQL不是測試使用開源工具最容易的事情。希望這種方法可能適合你。

FakeItEasy沒有與JustMock的ReturnCollection完全相同的方法,可以讓您嘲笑ITable返回IEnumerable。你有一個選擇是創建一個類似於here所示的MockableTable。然後填充你的表,你可以有像

private ITable<Employee> GetFakeEmployees() { 
    List<Employee> sampleData = /* fill it up with employees */ 
    var employeeTable = new MockableTable<Employee>(null, sampleData.AsQuerable());     
    return employeeTable; 
} 

此外,FakeItEasy不會攔截員工財產的DataContext的,因爲它是一個具體類的非虛擬財產。您可以創建一個簡單的自定義基類並讓MyDataContext類直接從中派生。

public abstract class CustomDataContext : DataContext, ICustomDataContext { 
} 

public interface ICustomDataContext { 
    ITable<Employee> { get; } 
} 

這裏的要點是利用你的模擬界面。然後在你的測試方法中,你將有:

[TestMethod] 
public void ShouldGetManagersByHireDate() { 
    var context = A.Fake<ICustomDataContext>(); 
    A.CallTo(()=> context.Employees).Returns(GetFakeEmployees()); 


    var repository = new EmployeeRepository(context); 
    var managers = repository.GetManagersByHireDate(new DateTime(2002, 1, 1), DateTime.Now); 

    Assert.AreEqual(1, managers.Count()); 
    Assert.AreEqual(1, managers.FirstOrDefault().ID); 
} 

我還沒有真正編譯過,但概念應該是穩定的。依靠抽象將使您的代碼更易於測試,並且更容易模擬。

希望這有些幫助。

+0

我一直希望避免涉及此方法的代碼量,但至少大部分是一次性的。謝謝 – frontsidebus 2013-05-11 16:37:41

2

我使用FakeItEasy完成此操作的方式是向DataContext添加接口,並將其作爲我的回收庫中的依賴項。例如。

public interface IMyDataContext : IDisposable 
{ 
    IQueryable<Employee> Employees { get; } 

    // etc. 
} 

public partial class MyDataContext: IMyDataContext 
{ 
    IQueryable<Message> IMyDataContext.Employees 
    { 
     get { return this.Employees; } 
    } 

    // etc. 
} 

public class EmployeeRepository 
{ 
    public EmployeeRepository(IMyDataContext context) 
    { 
     // etc. 
    } 
} 

而且在我的測試:

var context = A.Fake<IMyDataContext>(); 
A.CallTo(() => context.Employees).Returns(new[] { new Employee { Name = "John", Name = "Fred" }.AsQueryable()); 
var repository = new EmployeeRepository(context) 

我不認爲周邊ITable任何考慮,是必需的。

+0

這是比我自己更優雅的解決方案。然而,使用顯式的接口實現仍然顯得有些髒 – cecilphillip 2013-04-02 20:28:18

+0

這並不理想;-) Linq2Sql codegen本身應該生成一個接口。很不可笑,恕我直言。如果它的設計者在單元測試方面給了一點點思考,那麼他們會首先添加這個。 – 2013-04-03 06:44:04

+0

這與EntityFramework和IDbSet 非常相似的情況也不是嗎?如果FakeItEasy像JustMock一樣爲你處理這些收集案例,那將是非常好的。 – cecilphillip 2013-04-03 20:11:04