珠海市网站建设_网站建设公司_服务器维护_seo优化
2026/1/17 18:58:54 网站建设 项目流程

,General topic : https://www.cnblogs.com/Mattcoder/p/8878481.html

Unit Test

Integration Test - NetCore

 

 

Integration Test - Net4.5 

Unit Test at all layers

Add FluentAssertions and NUnit

 test-test the layered class, 

from controller (test the action result base on conditions)

to sevice

to repo

Focus is on verify whether the filtering behavior on the EF is correctly returnning desired entities

Fill the DBSet with test data that simulate the data populated from DB

namespace Wrox.BooksRead.Web.Tests.Repository
{public static class DbSetExtension{public static void SetDataSource<T>(this Mock<DbSet<T>> mockSet, IList<T> source) where T : class{var data = source.AsQueryable();mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(data.Provider);mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression);mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType);mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());}}
}

Second example

 

namespace XOProject.Tests
{internal static class DbSetExtension{public static void MockDbSet<T>(this Mock<DbSet<T>> mockSet, IEnumerable<T> source) where T:class{var list = source.AsQueryable();mockSet.As<IAsyncEnumerable<T>>().Setup(m => m.GetEnumerator()).Returns(new TestUseAsyncEnumerator<T>(list.GetEnumerator()));mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(new TestUseAsyncQueryProvider<T>(list.Provider));mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(list.Expression);mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(list.ElementType);mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(list.GetEnumerator());}}}
using Microsoft.EntityFrameworkCore.Query.Internal;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;namespace XOProject.Tests
{/// <summary>/// The type is to mock IAsyncQueryProvider which is rquired in IQuerable async methods/// </summary>/// <typeparam name="TEntity"></typeparam>internal class TestUseAsyncQueryProvider<TEntity> : IAsyncQueryProvider{private readonly IQueryProvider _inner;internal TestUseAsyncQueryProvider(IQueryProvider inner){_inner = inner;}public IQueryable CreateQuery(Expression expression){return new TestUseAsyncEnumerable<TEntity>(expression);}public IQueryable<TElement> CreateQuery<TElement>(Expression expression){return new TestUseAsyncEnumerable<TElement>(expression);}public object Execute(Expression expression){return _inner.Execute(expression);}public TResult Execute<TResult>(Expression expression){return _inner.Execute<TResult>(expression);}public IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression){return new TestUseAsyncEnumerable<TResult>(expression);}public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken){return Task.FromResult(Execute<TResult>(expression));}}internal class TestUseAsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T>{public TestUseAsyncEnumerable(IEnumerable<T> enumerable): base(enumerable){ }public TestUseAsyncEnumerable(Expression expression): base(expression){ }public IAsyncEnumerator<T> GetEnumerator(){return new TestUseAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());}IQueryProvider IQueryable.Provider{get { return new TestUseAsyncQueryProvider<T>(this); }}}internal class TestUseAsyncEnumerator<T> : IAsyncEnumerator<T>{private readonly IEnumerator<T> _inner;public TestUseAsyncEnumerator(IEnumerator<T> inner){_inner = inner;}public void Dispose(){_inner.Dispose();}public T Current{get{return _inner.Current;}}public Task<bool> MoveNext(CancellationToken cancellationToken){return Task.FromResult(_inner.MoveNext());}}}
AsyncEnumerator

 

 

 

 [Test]public async Task UpdateLatestPrice_ShouldUpdateMostRecentPrice(){// Arrangevar hourRates = new List<HourlyShareRate>() {new HourlyShareRate {Symbol = "CBI",Rate = 330.0M,TimeStamp = new DateTime(2019, 08, 17, 5, 0, 0)},new HourlyShareRate {Symbol = "CBI",Rate = 130.0M,TimeStamp = new DateTime(2020, 08, 17, 5, 0, 0)},new HourlyShareRate {Symbol = "CBI",Rate = 430.0M,TimeStamp = new DateTime(2018, 08, 17, 5, 0, 0)}};var mockSet = new Mock<DbSet<HourlyShareRate>>();mockSet.MockDbSet<HourlyShareRate>(hourRates);HourlyShareRate share = null;var mockContext = new Mock<ExchangeContext>();var mockRepository = new Mock<ShareRepository>(mockContext.Object);var shareController = new ShareController(mockRepository.Object);mockContext.Setup(i => i.Set<HourlyShareRate>()).Returns(mockSet.Object);mockRepository.Setup(i => i.UpdateAsync(It.IsAny<HourlyShareRate>())).Returns(Task.FromResult<object>(null)).Callback<HourlyShareRate>((p) => { share = p; });// Act
shareController.UpdateLastPrice("CBI");// AssertAssert.AreEqual(new DateTime(2020, 08, 17, 5, 0, 0), share.TimeStamp);Assert.AreEqual(10.0M, share.Rate);}
Test Code

 

Use Nnuit to assert exception throwed.

 

 

Integration Test

.NET CORE

Add reference to 

 

.NET 4.5 

Integration Test is expensive, this will focus on a happy path end to end from controller to repo to DB and finally verfiy the data bind to the view

[TestMethod][TestCategory("Integration Test")]public void GetAllAction_WhenCall_ShouldReturnProductInFutureOnlyToView(){//ArranageProduct[] products = new[]{ new Product { Id = 100, CreateDate = DateTime.Now.AddDays(1), Name = "Dummy1", Category = 0, Price = 0 } ,new Product { Id = 101, CreateDate = DateTime.Now.AddDays(2), Name = "Dummy2", Category = 0, Price = 0 },new Product { Id = 102, CreateDate = DateTime.Now.AddDays(-2), Name = "DummyObsolete", Category = 0, Price = 0 } };Category category = new Category { Id = 0, Name = "Dummy Category" };try{context.Categories.Add(category);context.Products.AddRange(products);context.SaveChanges();//Act DummyController controller = new DummyController(new UnitOfWork());var result = controller.GetAllAction();//Assertvar resultProducts = result.ViewData.Model as List<Wrox.BooksRead.Web.Models.Product>;resultProducts.Should().HaveCount(2);}finally{//Tear Down
                context.Products.RemoveRange(products);context.Categories.Remove(category);context.SaveChanges();}}

 Add nuit to better support transcaction scope , to make nunit test visible on test explorer, we need to add nunit 2 test adpater at tool->extension and updates

Add an attribute class that inherit ITestAction which is AOP design to insert an action before and after test execution

public class Isolated : Attribute, ITestAction{private TransactionScope transcope;public ActionTargets Targets{get {   return ActionTargets.Test;}}public void AfterTest(ITest test){transcope.Dispose();}public void BeforeTest(ITest test){transcope = new TransactionScope();}}

Apply the attribution to integration test that leveage DB transaction

 [Test, Isolated][Category("Integration Test")]public void GetUserNotification_WhenCall_ShouldReturnCorrectCountOfNotification(){//ArranageProduct[] products = new[] { new Product { Id = 100, CreateDate = DateTime.Now.AddDays(1), Name = "Dummy1", Category = 0, Price = 0 } };//, new Product { Id = 101, CreateDate = DateTime.Now.AddDays(2), Name = "Dummy2", Category = 0, Price = 0 },//    new Product { Id = 102, CreateDate = DateTime.Now.AddDays(-2), Name = "DummyObsolete", Category = 0, Price = 0 } };var productNotification = new ProductNotification{Id = 1,Product = products[0],Notification = string.Format(Utility.PRODUCT_PRICE_CHANGE_NOTIFICATION,new object[] {products[0].Id,products[0].Name,products[0].Price.ToString(),2}) };productNotification.UserProductNotifications.Add(new UserProductNotification { Id = 1, UserId = "1234", IsRead = 0, ProductNotificationId = 1 });var user = new AspNetUser(){Id = "1234",Name = "mockuser",UserName = "matt",EmailConfirmed = true,LockoutEnabled = true,PhoneNumberConfirmed = true,TwoFactorEnabled = true,AccessFailedCount = 0,};Category category = new Category { Id = 0, Name = "Dummy Category" };try{context.AspNetUsers.Add(user);context.Categories.Add(category);context.Products.AddRange(products);context.ProductNotifications.Add(productNotification);context.SaveChanges();//Act UserNotificationController controller = new UserNotificationController(new UnitOfWork());var result = controller.GetUserNotification("1234");//Assertresult.Should().HaveCount(1);}catch (Exception ex){System.Diagnostics.Debug.Write(ex.Message);}finally{              }}

 

and domain class.each 

class can have a dedicated test class.

use the method wirh naming convention of Method_Condition_Result.each methos

shud be aroind 5-10 lins of code and only one aseestion.

repo test requires Mock(DbSetl) object, mainly to test filtered condition really effective.

 

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询