如何測試(二)

測試主專案(WebApi)

建立測試專案

測試專案名稱:ApiController.Tests

在此專案會需要偽造的物件如下:

  • Response
  • Request

加入Nuget套件

  • NUnit
  • Moq
  • EntityFramework
  • Newtonsoft.Json
  • Microsoft.AspNet.WebApi.Core

加入專案參考

  • BusinessEntities
  • BusinessServices
  • DataModel
  • TestsHelper
  • WebApi

開始實作

加入以下的檔案

ProductControllerTest.cs

透過HttpClient加入Token至Request的Header去摸擬Authentication(授權)和Authorization(驗證)

using BusinessEntities;
using BusinessServices;
using BusinessServices.Tests;
using DataModel;
using DataModel.UnitOfWork;
using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Hosting;
using TestHelper;
using WebApi.Controllers;
using WebApi.ErrorHelper;

namespace ApiController.Tests
{
    public class ProductControllerTest
    {
        #region Variables

        private IProductServices _productService;
        private ITokenServices _tokenService;
        private IUnitOfWork _unitOfWork;
        private List<Products> _products;
        private List<Tokens> _tokens;
        private GenericRepository<Products> _productRepository;
        private GenericRepository<Tokens> _tokenRepository;
        private WebApiDbEntities _dbEntities;
        private HttpClient _client;

        private HttpResponseMessage _response;
        private string _token;
        private const string ServiceBaseURL = "http://localhost:50875/";

        #endregion

        [OneTimeSetUp]
        public void Setup()
        {
            _products = SetUpProducts();
            _tokens = SetUpTokens();
            _dbEntities = new Mock<WebApiDbEntities>().Object;
            _tokenRepository = SetUpTokenRepository();
            _productRepository = SetUpProductRepository();
            var unitOfWork = new Mock<IUnitOfWork>();
            unitOfWork.SetupGet(s => s.ProductRepository).Returns(_productRepository);
            unitOfWork.SetupGet(s => s.TokenRepository).Returns(_tokenRepository);
            _unitOfWork = unitOfWork.Object;
            _productService = new ProductServices(_unitOfWork);
            _tokenService = new TokenServices(_unitOfWork);
            _client = new HttpClient { BaseAddress = new Uri(ServiceBaseURL) };
            var tokenEntity = _tokenService.GenerateToken(1);
            _token = tokenEntity.AuthToken;
            _client.DefaultRequestHeaders.Add("Token", _token);
        }

        [SetUp]
        public void ReInitializeTest()
        {
            _client = new HttpClient { BaseAddress = new Uri(ServiceBaseURL) };
            _client.DefaultRequestHeaders.Add("Token", _token);
        }

        [TearDown]
        public void DisposeTest()
        {
            if (_response != null)
                _response.Dispose();
            if (_client != null)
                _client.Dispose();
        }

        private GenericRepository<Products> SetUpProductRepository()
        {
            // Initialise repository
            var mockRepo = new Mock<GenericRepository<Products>>(MockBehavior.Default, _dbEntities);

            // Setup mocking behavior
            mockRepo.Setup(p => p.GetAll()).Returns(_products);

            mockRepo.Setup(p => p.GetByID(It.IsAny<int>()))
            .Returns(new Func<int, Products>(
            id => _products.Find(p => p.ProductId.Equals(id))));

            mockRepo.Setup(p => p.Insert((It.IsAny<Products>())))
            .Callback(new Action<Products>(newProduct =>
            {
                var maxProductID = _products.Last().ProductId;
                var nextProductID = maxProductID + 1;
                newProduct.ProductId = nextProductID;
                _products.Add(newProduct);
            }));

            mockRepo.Setup(p => p.Update(It.IsAny<Products>()))
            .Callback(new Action<Products>(prod =>
            {
                var oldProduct = _products.Find(a => a.ProductId == prod.ProductId);
                oldProduct = prod;
            }));

            mockRepo.Setup(p => p.Delete(It.IsAny<Products>()))
            .Callback(new Action<Products>(prod =>
            {
                var productToRemove =
        _products.Find(a => a.ProductId == prod.ProductId);

                if (productToRemove != null)
                    _products.Remove(productToRemove);
            }));

            // Return mock implementation object
            return mockRepo.Object;
        }

        private GenericRepository<Tokens> SetUpTokenRepository()
        {
            // Initialise repository
            var mockRepo = new Mock<GenericRepository<Tokens>>(MockBehavior.Default, _dbEntities);

            // Setup mocking behavior
            mockRepo.Setup(p => p.GetAll()).Returns(_tokens);

            mockRepo.Setup(p => p.GetByID(It.IsAny<int>()))
            .Returns(new Func<int, Tokens>(
            id => _tokens.Find(p => p.TokenId.Equals(id))));

            mockRepo.Setup(p => p.Insert((It.IsAny<Tokens>())))
            .Callback(new Action<Tokens>(newToken =>
            {
                var maxTokenID = _tokens.Last().TokenId;
                var nextTokenID = maxTokenID + 1;
                newToken.TokenId = nextTokenID;
                _tokens.Add(newToken);
            }));

            mockRepo.Setup(p => p.Update(It.IsAny<Tokens>()))
            .Callback(new Action<Tokens>(token =>
            {
                var oldToken = _tokens.Find(a => a.TokenId == token.TokenId);
                oldToken = token;
            }));

            mockRepo.Setup(p => p.Delete(It.IsAny<Tokens>()))
            .Callback(new Action<Tokens>(prod =>
            {
                var tokenToRemove =
        _tokens.Find(a => a.TokenId == prod.TokenId);

                if (tokenToRemove != null)
                    _tokens.Remove(tokenToRemove);
            }));

            // Return mock implementation object
            return mockRepo.Object;
        }

        [Test]
        public void GetAllProductsTest()
        {
            var productController = new ProductController(_productService)
            {
                //摸擬發出的Request
                Request = new HttpRequestMessage
                {
                    Method = HttpMethod.Get,
                    RequestUri = new Uri(ServiceBaseURL + "v1/Products/Product/all")
                }
            };
            //初始化Request會用到
            productController.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());
            //取得ProductController裡回傳的Response
            _response = productController.Get();

            var responseResult = JsonConvert.DeserializeObject<List<Products>>(_response.Content.ReadAsStringAsync().Result);
            Assert.AreEqual(_response.StatusCode, HttpStatusCode.OK);
            Assert.AreEqual(responseResult.Any(), true);
            var comparer = new ProductComparer();
            CollectionAssert.AreEqual(
            responseResult.OrderBy(product => product, comparer),
            _products.OrderBy(product => product, comparer), comparer);
        }

        [Test]
        public void GetProductByIdTest()
        {
            var productController = new ProductController(_productService)
            {
                Request = new HttpRequestMessage
                {
                    Method = HttpMethod.Get,
                    RequestUri = new Uri(ServiceBaseURL + "v1/Products/Product/productid/2")
                }
            };
            productController.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());

            _response = productController.Get(2);

            var responseResult = JsonConvert.DeserializeObject<Products>(_response.Content.ReadAsStringAsync().Result);
            Assert.AreEqual(_response.StatusCode, HttpStatusCode.OK);
            AssertObjects.PropertyValuesAreEquals(responseResult,
            _products.Find(a => a.ProductName.Contains("Mobile")));
        }

        [Test]
        //[ExpectedException("WebApi.ErrorHelper.ApiDataException")]
        public void GetProductByWrongIdTest()
        {
            var productController = new ProductController(_productService)
            {
                Request = new HttpRequestMessage
                {
                    Method = HttpMethod.Get,
                    RequestUri = new Uri(ServiceBaseURL + "v1/Products/Product/productid/10")
                }
            };
            productController.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());

            var ex = Assert.Throws<ApiDataException>(() => productController.Get(10));
            Assert.That(ex.ErrorCode, Is.EqualTo(1001));
            Assert.That(ex.ErrorDescription, Is.EqualTo("No product found for this id."));

        }

        [Test]
        // [ExpectedException("WebApi.ErrorHelper.ApiException")]
        public void GetProductByInvalidIdTest()
        {
            var productController = new ProductController(_productService)
            {
                Request = new HttpRequestMessage
                {
                    Method = HttpMethod.Get,
                    RequestUri = new Uri(ServiceBaseURL + "v1/Products/Product/productid/-1")
                }
            };
            productController.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());

            var ex = Assert.Throws<ApiException>(() => productController.Get(-1));
            Assert.That(ex.ErrorCode, Is.EqualTo((int)HttpStatusCode.BadRequest));
            Assert.That(ex.ErrorDescription, Is.EqualTo("Bad Request..."));
        }

        /// <summary>
        /// Create product test
        /// </summary>
        [Test]
        public void CreateProductTest()
        {
            var productController = new ProductController(_productService)
            {
                Request = new HttpRequestMessage
                {
                    Method = HttpMethod.Post,
                    RequestUri = new Uri(ServiceBaseURL + "v1/Products/Product/Create")
                }
            };
            productController.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());

            var newProduct = new ProductEntity()
            {
                ProductName = "Android Phone"
            };

            var maxProductIDBeforeAdd = _products.Max(a => a.ProductId);
            newProduct.ProductId = maxProductIDBeforeAdd + 1;
            productController.Post(newProduct);
            var addedproduct = new Products() {
                ProductName = newProduct.ProductName,
                ProductId = newProduct.ProductId
            };
            AssertObjects.PropertyValuesAreEquals(addedproduct, _products.Last());
            Assert.That(maxProductIDBeforeAdd + 1, Is.EqualTo(_products.Last().ProductId));
        }

        /// <summary>
        /// Update product test
        /// </summary>
        [Test]
        public void UpdateProductTest()
        {
            var productController = new ProductController(_productService)
            {
                Request = new HttpRequestMessage
                {
                    Method = HttpMethod.Put,
                    RequestUri = new Uri(ServiceBaseURL + "v1/Products/Product/Modify")
                }
            };
            productController.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());

            var firstProduct = _products.First();
            firstProduct.ProductName = "Laptop updated";
            var updatedProduct = new ProductEntity() {
                ProductName = firstProduct.ProductName,
                ProductId = firstProduct.ProductId
            };
            productController.Put(firstProduct.ProductId, updatedProduct);
            Assert.That(firstProduct.ProductId, Is.EqualTo(1)); // hasn't changed
        }

        /// <summary>
        /// Delete product test
        /// </summary>
        [Test]
        public void DeleteProductTest()
        {
            var productController = new ProductController(_productService)
            {
                Request = new HttpRequestMessage
                {
                    Method = HttpMethod.Put,
                    RequestUri = new Uri(ServiceBaseURL + "v1/Products/Product/Remove")
                }
            };
            productController.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());

            int maxID = _products.Max(a => a.ProductId); // Before removal
            var lastProduct = _products.Last();

            // Remove last Product
            productController.Delete(lastProduct.ProductId);
            Assert.That(maxID, Is.GreaterThan(_products.Max(a => a.ProductId))); // Max id reduced by 1
        }

        // <summary>
        /// Delete product test with invalid id
        /// </summary>
        [Test]
        public void DeleteProductInvalidIdTest()
        {
            var productController = new ProductController(_productService)
            {
                Request = new HttpRequestMessage
                {
                    Method = HttpMethod.Put,
                    RequestUri = new Uri(ServiceBaseURL + "v1/Products/Product/remove")
                }
            };
            productController.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());

            var ex = Assert.Throws<ApiException>(() => productController.Delete(-1));
            Assert.That(ex.ErrorCode, Is.EqualTo((int)HttpStatusCode.BadRequest));
            Assert.That(ex.ErrorDescription, Is.EqualTo("Bad Request..."));
        }

        /// <summary>
        /// Delete product test with wrong id
        /// </summary>
        [Test]
        public void DeleteProductWrongIdTest()
        {
            var productController = new ProductController(_productService)
            {
                Request = new HttpRequestMessage
                {
                    Method = HttpMethod.Put,
                    RequestUri = new Uri(ServiceBaseURL + "v1/Products/Product/remove")
                }
            };
            productController.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());

            int maxID = _products.Max(a => a.ProductId); // Before removal

            var ex = Assert.Throws<ApiDataException>(() => productController.Delete(maxID + 1));
            Assert.That(ex.ErrorCode, Is.EqualTo(1002));
            Assert.That(ex.ErrorDescription, Is.EqualTo("Product is already deleted or not exist in system."));
        }

        private static List<Products> SetUpProducts()
        {
            var prodId = new int();
            var products = DataInitializer.GetAllProducts();
            foreach (Products prod in products)
                prod.ProductId = ++prodId;
            return products;
        }

        private static List<Tokens> SetUpTokens()
        {
            var tokId = new int();
            var tokens = DataInitializer.GetAllTokens();
            foreach (Tokens tok in tokens)
                tok.TokenId = ++tokId;
            return tokens;
        }

        [OneTimeTearDown]
        public void DisposeAllObjects()
        {
            _tokenService = null;
            _productService = null;
            _unitOfWork = null;
            _tokenRepository = null;
            _productRepository = null;
            _tokens = null;
            _products = null;
            if (_response != null)
                _response.Dispose();
            if (_client != null)
                _client.Dispose();
        }
    }
}

--

偽造一個Request的方式(放置於ProductControllerTest.cs裡)

var productController = new ProductController(_productService)
{
    //摸擬發出的Request(方法一)
    Request = new HttpRequestMessage
    {
        Method = HttpMethod.Get,
        RequestUri = new Uri(ServiceBaseURL + "v1/Products/Product/all")
    }
    //摸擬發出的Request(方法二)
    Request = new HttpRequestMessage()
};
//初始化Request會用到
productController.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());
//取得ProductController裡回傳的Response
_response = productController.Get();

實際發出一個Post的方式(未在ProductControllerTest.cs裡)

//建立HttpClient
var client = new HttpClient { BaseAddress = new Uri(ServiceBaseURL) };
//加入你的Http Header
client.DefaultRequestHeaders.Add("Authorization", "Basic YWtoaWw6YWtoaWw=");
//實際送出HttpPost並取得結果
_response = client.PostAsync("login", null).Result;
//實際送出HttpGet並取得結果
//_response = client.GetAsync("v1/Products/Product/allproducts/").Result;

//response 常見取得結果的方式
//_response.Headers
//_response.Content.ReadAsStringAsync().Result
//_response.StatusCode

results matching ""

    No results matching ""