В этом случае макет IFormFile
для возврата потока файлов в тесте и передачи его тестируемому действию.Убедитесь, что все другие необходимые зависимости удовлетворены.
public class TestClass {
private MyController _controller;
public TestClass() {
_controller = new MyController ();
}
[Fact]
public void Upload_WhenCalled() {
//Arrange
var content = File.OpenRead(@"C:\myfile.xlsx");
var file = new Mock<IFormFile>();
file.Setup(_ => _.OpenReadStream()).Returns(content);
//Act
var result = _controller.UploadFile(file.Object);
//Assert
//...
}
}
Теперь, хотя это должно помочь вам справиться с текущей проблемой, вы должны действительно принять совет, предложенный другими ответами об абстрагировании этой тесной связи ExcelPackage
изконтроллера в свою собственную заботу.Сделал бы модульное тестирование контроллера проще в изоляции.
При необходимости вы всегда можете выполнить интеграционный тест обертки отдельно.
Упрощенный пример интерфейса, абстрагирующегося от того, что в настоящее время находится в контроллере
public interface IExcelService {
Task<JArray> GetDataAsync(Stream stream);
}
, которыйбудет иметь реализацию, которая отражает код в контроллере
public class ExcelService: IExcelService {
public async Task<JArray> GetDataAsync(Stream stream) {
JArray data = new JArray();
using (ExcelPackage package = new ExcelPackage(stream)) {
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
if (worksheet.Dimension != null) {
data = await Task.Run(() => createJson(worksheet));
}
}
return data;
}
private JArray createJson(ExcelWorksheet worksheet) {
JArray data = new JArray();
int colCount = worksheet.Dimension.End.Column; //get Column Count
int rowCount = worksheet.Dimension.End.Row; //get row count
for (int row = 1; row <= rowCount; row++) {
JObject jobject = new JObject();
for (int col = 1; col <= colCount; col++) {
var value = worksheet.Cells[row, col].Value;
//Excel has 2 columns and I want to create a json from that.
if (col == 1) {
jObject.Add("ID", rowValue.ToString());
} else {
jObject.Add("Name", rowValue.ToString());
}
data.Add(jObject);
}
}
return data;
}
}
Теперь контроллер можно упростить, следуя принципу явных зависимостей
public class MyController : Controller {
private readonly IExcelService excel;
public MyController(IExcelService excel) {
this.excel = excel;
}
[HttpPost("upload")]
public async Task<IActionResult> UploadFile(IFormFile file) {
JArray data = await excel.GetDataAsync(myFile.OpenReadStream());
if(data.Count == 0)
return BadRequest("File is blank.");
return Ok(data);
}
}
Вы бы сделалиубедитесь, что интерфейс и реализация зарегистрированы в платформе Dependency Inversion в Startup
services.AddScoped<IExcelService, ExcelService>();
Так что теперь контроллер касается только того, что он должен делать при вызове во время выполнения.У меня нет причин заниматься вопросами реализации
public class MyControllerTests {
[Fact]
public async Task Upload_WhenCalled() {
//Arrange
var content = new MemoryStream();
var file = new Mock<IFormFile>();
file.Setup(_ => _.OpenReadStream()).Returns(content);
var expected = new JArray();
var service = new Mock<IExcelService>();
service
.Setup(_ => _.GetDataAsync(It.IsAny<Stream>()))
.ReturnsAsync(expected);
var controller = new MyController(service.Object);
//Act
var result = await controller.UploadFile(file.Object);
//Assert
service.Verify(_ => _.GetDataAsync(content));
//...other assertions like if result is OkContentResult...etc
}
}
Чтобы провести интеграционный тест, включающий в себя реальный файл, вы можете протестировать службу
public class ExcelServiceTests {
[Fact]
public async Task GetData_WhenCalled() {
//Arrange
var stream = File.OpenRead(@"C:\myfile.xlsx");
var service = new ExcelService();
//Act
var actual = await service.GetDataAsync(stream);
//Assert
//...assert the contents of actual data.
}
}
Теперь можно протестировать каждую задачусвой.