問題:
我是使用 xunit 在 c# 中撰寫單元測驗的新手。所以我試圖模擬 MongoDB 連接。在我的專案中,我使用了存盤庫模式,我使用了這樣的作業單元。所以我通過它訪問每個存盤庫。所以作業單元代碼在這里。
namespace QuestionBank.API.Repositories
{
public class UnitOfWork : IUnitOfWork
{
public readonly IQuestionsBankDBContext _context;
private readonly ILogger<UnitOfWork> _logger;
private Dictionary<Type, object> repositories;
private IQuestionsRepository _questionsRepository;
private ICampaignQuestionsRepository _campaignQuestionsRepository;
private ICandidateAnswerRepository _candidateAnswerRepository;
private IIntergrationEventLogRepository _integrationEventLogRepository;
private IControlRepository _controlRepository;
public UnitOfWork(IQuestionsBankDBContext context, ILogger<UnitOfWork> logger)
{
_context = context;
_logger = logger;
}
public IQuestionsRepository QuestionsRepository
{
get
{
this._questionsRepository = new QuestionsRepository(_context as IQuestionsBankDBContext, this, _logger);
return this._questionsRepository;
}
}
public ICandidateAnswerRepository CandidateAnswerRepository
{
get
{
this._candidateAnswerRepository = new CandidateAnswerRepository(_context as IQuestionsBankDBContext, this, _logger);
return this._candidateAnswerRepository;
}
}
public ICampaignQuestionsRepository CampaignQuestionsRepository
{
get
{
this._campaignQuestionsRepository = new CampaignQuestionsRepository(_context as IQuestionsBankDBContext, this, _logger);
return this._campaignQuestionsRepository;
}
}
public IIntergrationEventLogRepository IntegrationEventLogRepository
{
get
{
this._integrationEventLogRepository = new IntergrationEventLogRepository(_context as IQuestionsBankDBContext, this, _logger);
return this._integrationEventLogRepository;
}
}
public IControlRepository ControlRepository
{
get
{
this._controlRepository = new ControlRepository(_context as IQuestionsBankDBContext, this, _logger);
return this._controlRepository;
}
}
public IGenericRepository<TDocument> GetRepository<TDocument>() where TDocument : IDocument
{
if (this.repositories == null)
{
this.repositories = new Dictionary<Type, object>();
}
var type = typeof(TDocument);
if (!this.repositories.ContainsKey(type))
{
this.repositories[type] = new GenericRepository<TDocument>(_context);
}
return (IGenericRepository<TDocument>)this.repositories[type];
}
}
}
因此,在模擬服務和存盤庫的單元測驗中,我需要將資料庫背景關系傳遞給 unitofwork。我是這樣試的。
var mockDbContext = new Mock<QuestionsBankDBContext>();
var dbContext = mockDbContext.Object;
var mock = new Mock<ILogger<UnitOfWork>>();
_logger = mock.Object;
unitOfWork = new UnitOfWork(dbContext, _logger);
questionsService = new QuestionsService(unitOfWork);
campaignQuestionsService = new CampaignQuestionsService(unitOfWork);
tokenService = new TokenService();
stringLocalizer = new Mock<IStringLocalizer<SharedResource>>();
questionBankIntergrationEventService = new Mock<IQuestionBankIntergrationEventService>();
questionsController = new QuestionsController(questionsService, campaignQuestionsService, stringLocalizer.Object, tokenService, questionBankIntergrationEventService.Object);
contextMock = new Mock<HttpContext>();
這是我的資料庫背景關系類。
using MongoDB.Driver;
using QuestionBank.API.Models;
namespace QuestionBank.API.Data
{
public class QuestionsBankDBContext : IQuestionsBankDBContext
{
public IMongoClient Client { get; set; }
public IMongoDatabase Database { get; set; }
public QuestionsBankDBContext(IQuestionBankDatabaseSettings settings)
{
Client = new MongoClient(settings.ConnectionString);
Database = Client.GetDatabase(settings.DatabaseName);
}
}
}
然后我寫了一個這樣的單元測驗。
[Theory]
[InlineData("61879e54e86be1fa5e41831f")]
[InlineData("61879e54e86be1fa5e41831e")]
public async Task GetQuestionById(string questionId)
{
var actionResult = await questionsController.GetQuestionById(questionId);
var result = actionResult as ObjectResult;
Assert.NotNull(result.Value);
if (result.StatusCode == (int)System.Net.HttpStatusCode.OK)
{
Assert.IsType<Questions>(result.Value);
}
else if (result.StatusCode == (int)System.Net.HttpStatusCode.NotFound)
{
Assert.Contains("ErrorCode", result.Value.ToString());
}
else if (result.StatusCode == (int)System.Net.HttpStatusCode.InternalServerError)
{
var code = (int)ErroCodes.InternalServerError;
Assert.Contains(code.ToString(), result.Value.ToString());
}
}
然后在運行時它給出

而我的問題控制器 GetQuestionById 就是這樣。
[HttpGet]
//[Authorize(Roles = "SuperAdmin,Admin")]
[Route("getquestionbyidfrombank")]
[ProducesResponseType(typeof(Questions), 200)]
[ProducesResponseType(typeof(string), 404)]
[ProducesResponseType(typeof(string), 500)]
public async Task<IActionResult> GetQuestionById([FromQuery] string questionId)
{
try
{
string errorText;
if (!string.IsNullOrEmpty(questionId))
{
var question = await
questionsService.GetQuestionById(questionId);
return Ok(question);
}
else
{
errorText = string.Format(stringLocalizer[Constants.ErrorCodeString],
(int)ErroCodes.SpecifiedItemNotFound,
stringLocalizer[Helper.ToEnumString(ErroCodes.SpecifiedItemNotFound)]);
return StatusCode(404, errorText);
}
}
catch (Exception ex)
{
string exceptionData =
$"Exception occured while getiing question by id. "
$"\nException Data: Message- {ex.Message}; "
$"InnerException- {ex.InnerException}; StackTrace- {ex.StackTrace}";
string errorText = string.Format(stringLocalizer[Constants.ErrorCodeString],
(int)ErroCodes.InternalServerError,
stringLocalizer[Helper.ToEnumString(ErroCodes.InternalServerError)]);
return StatusCode(500, errorText);
}
}
這就是我進行服務實體化的方式。
public QuestionsService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
通過 id 函式獲取問題
public async Task<Questions> GetQuestionById(string id)
{
var question = await _unitOfWork.QuestionsRepository.FindByIdAsync(id);
return question;
}
有人可以幫助我正確撰寫此單元測驗并解決此問題。我嘗試了很多來找到一種方法來做到這一點,但我無法做到。謝謝
uj5u.com熱心網友回復:
不要 - 僅僅因為某些東西可以被嘲笑,并不意味著它應該被嘲笑。
相反,您可以使用 docker 映像來運行 Mongo,為每個測驗類 init 洗掉和創建一個資料庫,每個測驗 init 洗掉集合。
在沒有 DB 的情況下測驗 DAL(資料訪問層)是在浪費時間,并且不會幫助您真正找到錯誤。
當您對其他組件進行單元測驗時,模擬整個 DAL 以回傳您期望的物件。
并且不要跳過為包含空/預填充-via-test-config-data 資料庫的整個服務撰寫測驗。
此外,您的欄位DbContext應該是私有的,而不是公共的,同時將 a 的常量實體傳遞DbContext給 MongoDB 是可以的,因為 MongoDB 背景關系是無狀態的(沒有事務和連接被池化),通常傳遞一個DbContextvia 建構式是錯誤的(因為關系DB 有事務并且連接不應該保持打開狀態),而是傳遞一個Func<DbContext>(例如public MyClass(Func<DbContext> contextConstructor)),它回傳建構式并具有DbContext實施IDisposable。這樣客戶端類就可以做到using (context = contextCreator()) { ... }。
uj5u.com熱心網友回復:
您應該創建介面的模擬而IQuestionsBankDBContext不是類QuestionsBankDBContext。除此之外,您的測驗不是單元測驗,它更像是集成測驗,因為您正在創建控制器和一些服務的實體,并且您只模擬應用程式的資料庫層。在單元測驗中,您應該只測驗單個層。如果您為控制器撰寫單元測驗,那么您應該模擬服務及其行為(控制器的直接依賴項)。
查看您的控制器方法,第一個單元測驗應該檢查當您傳遞非 null 和非空問題 ID 時,您的方法是否回傳 OkResult。對于這個測驗,模擬questionsService可以回傳一個問題物件。
下一個測驗應該檢查相反的情況,當它得到空字串時,它應該回傳一個代碼為 404 的回應。(在我看來它應該是 400,但我們正在談論單元測驗)
最后一個測驗應該檢查例外處理。例如,您在測驗中傳遞了一個有效的 questionId,但模擬questionService拋出例外。在此測驗中,您可以斷言回應的狀態代碼為 500。
如果您想使用一種測驗方法(XUnit 中的理論)測驗多個案例,那么所有這些案例都應該具有相同的結果,或者您應該為每個案例提供預期的結果。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/359940.html
