I tried to write unit test for getMark()
and faced problem with Moq
, with which I'm not familiar. I have no idea what method and object properly mock in order to unit test getMark()
Here is my MarkServiceClass
containing getMark()
public class MarkService : IMarkService
{
IMarkService _markService;
IStdService _stdService;
IStdService _stdMService;
RClass cs;
public MarkService(IMarkService markService, IStdService stdService, IStdService stdMService)
{
_markService = markService;
_stdService = stdService;
_stdMService = stdMService;
}
public bool Init(int sID, string pID, string year)
{
try
{
cs = new RClass ();
cs.sLevel = __stdService.GetAsIQueryable().FirstOrDefault(x => x.UID == pID);
var mInfo = __stdMService.GetSTDM(sID, pID, year);
cs.Type = mInfo.CalculateAmount;
return true;
}
catch
{
return false;
}
}
public MarkVM getMark(int sID, string pID, string year)
{
var output=Init(sID, pID, year);
if (!output)
return null;
int sGrade= 0;
int sMark= 0;
//here are conditions where sGrade and sMark used
return new MarkVM
{
Grade = sGrade,
Mark = sMark
};
}
}
and MarkVM
public class MarkVM
{
public int Grade { get; set; }
public int Mark { get; set; }
}
CodePudding user response:
A basic Moq
coding will be like this
[Test]
public void Test1()
{
var mock = new Mock<IMarkService>();
mock.Setup(p => p.getMark(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>())).Returns(new MarkVM());
mock.Verify(p => p.getMark(1001, "P001", "2022"), Times.Once());
}
CodePudding user response:
The code you shared is not complete so I had to make some assumptions to give you an example how to unit test getMark
public class MarkVM
{
public int Grade { get; set; }
public int Mark { get; set; }
}
Not knowing what RClass is, I define it with minimal requirements
public class RClass {
public String Uid { get; set; }
public string sLevel { get; set; }
public int Type { get; set; }
}
Same for this Info your service retrieves with GetSTDM
public class Info
{
public int CalculateAmount { get; set; }
}
Now come the interfaces. This is definitely required if you want to mock
public interface IStdService
{
List<RClass> GetAsIQueryable();
Info GetSTDM(int sID, string pID, string year);
}
Those 2 methods are the ones you'll want to mock if you unit test getMark. Mocking getMark itself will only allow you to check it is called, but not its behavior which is the purpose of unit testing.
Now the main class. I removed the injection of IMarkService in the constructor because I really don't see why you would do that: Markservice implements IMarkService here. For any reason you use 2 instances of IStdService, I kelpt that but then you need to inject it too.
public class MarkService : IMarkService
{
private IStdService __stdService;
private IStdService __stdMService;
public RClass cs;
public MarkService(IStdService stdMService, IStdService stdService)
{
__stdMService = stdMService;
__stdService = stdService;
}
public bool Init(int sID, string pID, string year)
{
try
{
cs = new RClass();
cs.sLevel = __stdService.GetAsIQueryable().FirstOrDefault(x => x.Uid == pID).sLevel;
var mInfo = __stdMService.GetSTDM(sID, pID, year);
cs.Type = mInfo.CalculateAmount;
return true;
}
catch
{
return false;
}
}
public MarkVM getMark(int sID, string pID, string year)
{
var output = Init(sID, pID, year);
if (!output)
return null;
int sGrade = 0;
int sMark = 0;
//here are conditions where sGrade and sMark used
return new MarkVM
{
Grade = sGrade,
Mark = sMark
};
}
}
Now comes the test. If you want to unit test getMark you could either mock Init from IMarkService, or consider the behavior comes from this Init and then you want to mock GetAsIQueryable and GetSTDM. I made the assumption second option is what you want.
using System.Collections.Generic;
using MarkServiceNS;
using Moq;// Moq framework where you'll find everything you need
using NUnit.Framework;// Using NUnit for unit test. Because I like it :-)
using NUnit.Framework.Constraints;
namespace UnitTestWithMoqExample
{
public class Tests
{
[SetUp]
public void Setup()
{
}
[Test]
public void getMark()
{
var mockedStdService = new Mock<IStdService>();
mockedStdService.Setup(x => x.GetAsIQueryable())
.Returns(new List<RClass> { new RClass { Uid = "uid", sLevel = "expected", Type = 1 } }); // Here you define what it the mocked result of GetAsIQueryable call.
var mockedStdMService = new Mock<IStdService>();
mockedStdMService.Setup(x => x.GetSTDM(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns(new Info { CalculateAmount = 1 });// Same here. You mock GetSTDM. The method parameters are not expected to change the behavior in my unit test, this is why I consider It.Any<T> so whatever you pass to the mock, the result will be the same.
// Here is the assertion. This should do the job
var service = new MarkServiceNS.MarkService(mockedStdMService.Object, mockedStdService.Object);
Assert.IsNotNull(service.getMark(1, "", ""));
Assert.IsInstanceOf(typeof(MarkVM), service.getMark(1, "", ""));
Assert.AreEqual(0, service.getMark(1, "", "").Grade);
Assert.AreEqual(0, service.getMark(1, "", "").Mark);
}
}
}