개체 목록에 대한 C # Create Mock Configuration.GetSection ( "Section : SubSection")
객관적인
단위 테스트에서 적용 범위를 향상시키기 위해 특정 섹션 "캐릭터 / 스킬"을로드하기 위해 Moq 및 XUnit을 사용하여 모의 객체를 만듭니다.
SUT (어떤 지점에서)는 설정을로드합니다.
var skills = Configuration.GetSection(“Character:Skills”);
다음 appSetting에서 :
{
"dummyConfig1": {
"Description": "bla bla bla...",
},
"Character": {
"Name": "John Wick",
"Description": "A retired hitman seeking vengeance for the killing of the dog given to him...",
"Skills": [
{
"Key": "CQC Combat",
"Id": "15465"
},
{
"Key": "Firearms",
"Id": "14321"
},
{
"Key": "Stealth",
"Id": "09674"
},
{
"Key": "Speed",
"Id": "10203"
}
],
"DummyConf2": "more bla bla bla..."
}
이전 읽기
이 게시물 (및 인터넷 검색의 결과로 다른 다른 게시물)을 읽은 결과, 원시 "문자열"데이터 유형 또는 새로운 Mock <IConfigurationSection> 객체 (설정 없음) 만 사용할 수 있음을 알았습니다 .
- 스택 오버플로-Configuration.GetSection ( "foo : bar") 모의 방법 ,
- IConfiguration 확장 메서드 모의
- 단위 테스트에서 IConfiguration Getvalue () 확장 메서드 모의
제약 : 실제 설정을로드하기 위해 appSetting 파일을 TestProject에 복사 (또는 MemoryStream 생성)하면이 시나리오를 해결할 수 있지만 테스트는 "Unit"대신 "Integration"이됩니다. I / O 종속성이 있기 때문입니다.
접근
코드의 아이디어 (나중에 표시됨)는 각 속성 (키 / ID)을 조롱 한 다음 다음과 유사한 트리에서 병합하는 것입니다.
- "문자"------ 읽을 구성, 사용
GetSection()후Get<T>()- "Skills"------ 병합 된 속성이있는 구성 목록
- "Key"- "CQC Combat"------ 기본 값 1
- "Id"- "15465"------ 기본 값 2
- "Skills"------ 병합 된 속성이있는 구성 목록
코드
var skillsConfiguration = new List<SkillsConfig>
{
new SkillsConfig { Key = "CQC Combat" , Id = "15465" },
new SkillsConfig { Key = "Firearms" , Id = "14321" },
new SkillsConfig { Key = "Stealh" , Id = "09674" },
new SkillsConfig { Key = "Speed" , Id = "10203" },
};
var configurationMock = new Mock<IConfiguration>();
var mockConfSections = new List<IConfigurationSection>();
foreach (var skill in skillsConfiguration)
{
var index = skillsConfiguration.IndexOf(skill);
//Set the Key string value
var mockConfSectionKey = new Mock<IConfigurationSection>();
mockConfSectionKey.Setup(s => s.Path).Returns($"Character:Skills:{index}:Key"); mockConfSectionKey.Setup(s => s.Key).Returns("Key"); mockConfSectionKey.Setup(s => s.Value).Returns(skill.Key); //Set the Id string value var mockConfSectionId = new Mock<IConfigurationSection>(); mockConfSectionId.Setup(s => s.Path).Returns($"Character:Skills:{index}:Id");
mockConfSectionId.Setup(s => s.Key).Returns("Id");
mockConfSectionId.Setup(s => s.Value).Returns(skill.Id);
//Merge the attribute "key/id" as Configuration section list
var mockConfSection = new Mock<IConfigurationSection>();
mockConfSection.Setup(s => s.Path).Returns($"Character:Skills:{index}");
mockConfSection.Setup(s => s.Key).Returns(index.ToString());
mockConfSection.Setup(s => s.GetChildren()).Returns(new List<IConfigurationSection> { mockConfSectionKey.Object, mockConfSectionId.Object });
//Add the skill object with merged attributes
mockConfSections.Add(mockConfSection.Object);
}
// Add the Skill's list
var skillsMockSections = new Mock<IConfigurationSection>();
skillsMockSections.Setup(cfg => cfg.Path).Returns("Character:Skills");
skillsMockSections.Setup(cfg => cfg.Key).Returns("Skills");
skillsMockSections.Setup(cfg => cfg.GetChildren()).Returns(mockConfSections);
//Mock the whole section, for using GetSection() method withing SUT
configurationMock.Setup(cfg => cfg.GetSection("Character:Skills")).Returns(skillsMockSections.Object);
예상 결과
원래 시스템을 실행하면 각각의 인스턴스화 된 목록이 표시됩니다. 스크린 샷은 다음과 같습니다.
모의 결과
위의 코드는 인스턴스화 된 목록 만 가져 오지만 모든 속성은 null을 반환합니다. 다음은 스크린 샷입니다.
답변
마지막으로 코드를 리팩토링하여 전체 foreach블록 을 제거하고 목록 초기화 var mockConfSections = new List<IConfigurationSection>();를 더 간단하고 깔끔한 코드 조각으로 대체했습니다 .
var fakeSkillSettings = skillsConfiguration.SelectMany(
skill => new Dictionary<string, string> {
{ $"Character:Skills:{skillsConfiguration.IndexOf(skill)}:Key", skill.Key }, { $"Character:Skills:{skillsConfiguration.IndexOf(skill)}:Id" , skill.Id },
});
var configBuilder = new ConfigurationBuilder();
var mockConfSections = configBuilder.AddInMemoryCollection(fakeSkillSettings)
.Build()
.GetSection("Character:Skills")
.GetChildren();
설명
이전 구현에서 모의 노드를 사용하여 구성 트리를 만들었으므로 각 노드에 대한 설정 및 반환이 필요했기 때문에 솔루션이 부풀려졌습니다.
Keep Configuration Settings in Memory 문서를 기반으로 LINQ SelectMany를 사용하여 평면화 된 키 / ID 사전으로 목록을 프로젝션 한 다음 메모리 구성을 빌드하고 마지막으로 "실제 노드"로 설정을 조롱하여 하나의 모의 설정을 생성했습니다.