Visual studio 如何在VisualStudio中编写Web API的测试代码?

Visual studio 如何在VisualStudio中编写Web API的测试代码?,visual-studio,asp.net-web-api,automated-tests,xunit,testcase,Visual Studio,Asp.net Web Api,Automated Tests,Xunit,Testcase,我对测试项目有点陌生。我目前有一个web api项目,其中包含Get、Put、Post和Delete方法。说到编写测试用例,我很困惑。我应该编写测试代码来测试Http URL吗 我的web api代码: // GET api/values/5 [HttpGet("{id}")] public IActionResult Get(string id) { using (var unitOfWork = new UnitOfWork(_db))

我对测试项目有点陌生。我目前有一个web api项目,其中包含Get、Put、Post和Delete方法。说到编写测试用例,我很困惑。我应该编写测试代码来测试Http URL吗

我的web api代码:

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(string id)
    {
        using (var unitOfWork = new UnitOfWork(_db))
        {
            var r = unitOfWork.Resources.Get(id);

            unitOfWork.Complete();

            Models.resource result = ConvertResourceFromCoreToApi(r);

            if (result == null)
            {
                return NotFound();
            }
            else
            {
                return Ok(result);
            }
        }
    }
在我的测试项目中,我被困在这里。我们正在使用Xunit。如何编写测试代码来测试Get方法?或者我应该编写代码来测试URL api/values/5,但如何测试呢

    [Fact]
    public void GetTest()
    {
        using (var unitOfWork = new UnitOfWork(new MockDatabase()))
        {

        }
    }

任何帮助都将不胜感激。

您需要对控制器进行一些设计更改,以使其易于测试。在您的操作中,您正在创建一个实例,这将使测试与控制器的假依赖关系变得困难。此外,您的控制器应该依赖于抽象而不是具体化,这将使控制器更易于测试

public class MyWebApiController : ApiController {
    private IUnitOfWork unitOfWork;

    public MyWebApiController(IUnitOfWork unitOfWork) {
       this.unitOfWork = unitOfWork;
    }

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(string id) {        
        var r = unitOfWork.Resources.Get(id);

        unitOfWork.Complete();

        Models.resource result = ConvertResourceFromCoreToApi(r);

        if (result == null) {
            return NotFound();
        } else {
            return Ok(result);
        }        
    }

    //...other code
}
请注意,控制器使用依赖项注入来注入
IUnitOfWork
。这使得控制器更易于测试,因为您可以在单元测试时注入其依赖项的模拟

从这里开始,只需创建一个控制器实例,并使用依赖项的模拟调用测试中的方法

[Fact]
public void GetTest() {
    //Arrange (Setup the parts needed to run test)
    var unitOfWork = new MockUnitOfWork(new MockDatabase());

    //Or using your mocking framework of choice
    //var unitOfWork = Mock.Of<IUnitOfWork>(); //this is using Moq

    var controller = new MyWebApiController(unitOfWork);
    var id = "Test Id value here";

    //Act (call the method under test)
    var result - controller.Get(id);

    //Assert (check results)
    //...Do your assertion pertaining to result of calling method under test
}
[事实]
公共无效GetTest(){
//安排(设置运行测试所需的部件)
var unitOfWork=new MockUnitOfWork(new MockDatabase());
//或者使用你选择的模拟框架
//var unitOfWork=Mock.Of();//这是使用Moq
var控制器=新的MyWebApicController(unitOfWork);
var id=“此处的测试id值”;
//Act(调用测试中的方法)
var结果-controller.Get(id);
//断言(检查结果)
//…执行与调用测试中方法的结果相关的断言
}

参考资料:

您需要对控制器进行一些设计更改,以便于测试。在您的操作中,您正在创建一个实例,这将使测试与控制器的假依赖关系变得困难。此外,您的控制器应该依赖于抽象而不是具体化,这将使控制器更易于测试

public class MyWebApiController : ApiController {
    private IUnitOfWork unitOfWork;

    public MyWebApiController(IUnitOfWork unitOfWork) {
       this.unitOfWork = unitOfWork;
    }

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(string id) {        
        var r = unitOfWork.Resources.Get(id);

        unitOfWork.Complete();

        Models.resource result = ConvertResourceFromCoreToApi(r);

        if (result == null) {
            return NotFound();
        } else {
            return Ok(result);
        }        
    }

    //...other code
}
请注意,控制器使用依赖项注入来注入
IUnitOfWork
。这使得控制器更易于测试,因为您可以在单元测试时注入其依赖项的模拟

从这里开始,只需创建一个控制器实例,并使用依赖项的模拟调用测试中的方法

[Fact]
public void GetTest() {
    //Arrange (Setup the parts needed to run test)
    var unitOfWork = new MockUnitOfWork(new MockDatabase());

    //Or using your mocking framework of choice
    //var unitOfWork = Mock.Of<IUnitOfWork>(); //this is using Moq

    var controller = new MyWebApiController(unitOfWork);
    var id = "Test Id value here";

    //Act (call the method under test)
    var result - controller.Get(id);

    //Assert (check results)
    //...Do your assertion pertaining to result of calling method under test
}
[事实]
公共无效GetTest(){
//安排(设置运行测试所需的部件)
var unitOfWork=new MockUnitOfWork(new MockDatabase());
//或者使用你选择的模拟框架
//var unitOfWork=Mock.Of();//这是使用Moq
var控制器=新的MyWebApicController(unitOfWork);
var id=“此处的测试id值”;
//Act(调用测试中的方法)
var结果-controller.Get(id);
//断言(检查结果)
//…执行与调用测试中方法的结果相关的断言
}

参考资料:

在对控制器进行真正的单元测试之前,您需要做一些更改。您需要将UnitOfWork类的实例传递到其构造函数中的控制器中。然后,控制器方法代码变为:

// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(string id)
{    
    var r = unitOfWork.Resources.Get(id);

    unitOfWork.Complete();

    Models.resource result = ConvertResourceFromCoreToApi(r);

    if (result == null)
    {
        return NotFound();
    }
    else
    {
        return Ok(result);
    }
然后在单元测试中执行以下操作:

[Fact]
public void GetTest()
{
    // Arrange
    // You really want to mock your unit of work so you can determine
    // what you are going to send back
    var unitOfWork = new MockUnitOfWork();
    var systemUnderTest = new Controller(unitOfWork);
    system.Request = new HttpRequestMessage();

    // Act
    var result = systemUnderTest.Get(1);

    // Assert
    // Here you need to verify that you got back the expected result
}
将UnitOfWork类注入控制器可能是另一个问题。马克·西曼在这个问题上有很好的见解,但可能有点超前。有许多不同的方法可以通过更简单的方法(但可能不是健壮的方法)实现这一点。谷歌是你的朋友。但是如果你有问题的话,再发一个问题


希望这能有所帮助。

在真正对控制器进行单元测试之前,您需要做一些更改。您需要将UnitOfWork类的实例传递到其构造函数中的控制器中。然后,控制器方法代码变为:

// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(string id)
{    
    var r = unitOfWork.Resources.Get(id);

    unitOfWork.Complete();

    Models.resource result = ConvertResourceFromCoreToApi(r);

    if (result == null)
    {
        return NotFound();
    }
    else
    {
        return Ok(result);
    }
然后在单元测试中执行以下操作:

[Fact]
public void GetTest()
{
    // Arrange
    // You really want to mock your unit of work so you can determine
    // what you are going to send back
    var unitOfWork = new MockUnitOfWork();
    var systemUnderTest = new Controller(unitOfWork);
    system.Request = new HttpRequestMessage();

    // Act
    var result = systemUnderTest.Get(1);

    // Assert
    // Here you need to verify that you got back the expected result
}
将UnitOfWork类注入控制器可能是另一个问题。马克·西曼在这个问题上有很好的见解,但可能有点超前。有许多不同的方法可以通过更简单的方法(但可能不是健壮的方法)实现这一点。谷歌是你的朋友。但是如果你有问题的话,再发一个问题


希望有帮助。

视情况而定。你在写单元测试还是集成测试?我相信是单元测试。你应该知道的。您可以在这里阅读更多关于单元与集成的内容:对于本例,您可以调用这些方法来对api进行单元测试。是的,我们正在编写单元测试。抱歉,这可能是一个愚蠢的问题,但如何从单元测试中调用控制器中的方法?在“using(var unitOfWork=new unitOfWork(new MockDatabase())”中,我应该使用var r=xxxController.Get(“some id”)之类的东西来调用该方法吗?MichaelDotKnox对您的回答非常好。随你的便,视情况而定。你在写单元测试还是集成测试?我相信是单元测试。你应该知道的。您可以在这里阅读更多关于单元与集成的内容:对于本例,您可以调用这些方法来对api进行单元测试。是的,我们正在编写单元测试。抱歉,这可能是一个愚蠢的问题,但如何从单元测试中调用控制器中的方法?在“using(var unitOfWork=new unitOfWork(new MockDatabase())”中,我应该使用var r=xxxController.Get(“some id”)之类的东西来调用该方法吗?MichaelDotKnox对您的回答非常好。去吧,谢谢你!那真的很有帮助!非常感谢。那真的很有帮助!谢谢你的回复。这对于开始学习WebAPI的单元测试是一个很好的参考!很乐意帮忙。如果答案有用,你可以投票表决。快乐编码!!!谢谢你的回复。这对于开始学习WebAPI的单元测试是一个很好的参考!很乐意帮忙。如果答案有用,你可以投票表决。快乐编码!!!