多语句事务中不允许创建数据库语句.在 TFS 自动生成上

本文关键字:TFS 自动生成 数据库语句 创建 语句 事务 不允许 | 更新日期: 2023-09-27 18:31:33

我在 TFS 上创建了一个 CI,但在测试自动化中遇到了此错误

Test method xx.xx.Tests.Controllers.TipoDeCanalesControllerTest.DeleteTipoDeCanal threw exception: 
System.Data.SqlClient.SqlException: CREATE DATABASE statement not allowed within multi-statement transaction.
    at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.Sq

该项目是一个 asp.net MVC 应用程序,单元测试正在测试 WebAPI 控制器,我也首先使用实体框架代码,它应该创建一个数据库。

http://screencast.com/t/fY7sZXeCy

测试代码是这样的:

 public class TipoDeCanalesControllerTest
    {
        [TestMethod]
        public void PostTipoDeCanal()
        {
            TipoDeCanalesController controller = NewController();
            // Act
            TipoDeCanal tipoDeCanal = new TipoDeCanal() { Descripcion = "Unit Test Des", Nombre = "Unit Test" };
            var response = new HttpResponseMessage();
            using (System.Transactions.TransactionScope ts = new System.Transactions.TransactionScope())
            {
                response = controller.PostTipoDeCanal(tipoDeCanal);
                ts.Dispose();
            }
            // Assert
            Assert.AreEqual(System.Net.HttpStatusCode.Created,
               response.StatusCode);
        }
        [TestMethod]
        public void PutTipoDeCanal()
        {
            TipoDeCanalesController controller = NewController();
            // Act
            TipoDeCanal tipoDeCanal = new TipoDeCanal() { Descripcion = "Unit Test Description", Nombre = "Unit Test" };
            var response = new HttpResponseMessage();
            using (System.Transactions.TransactionScope ts = new System.Transactions.TransactionScope())
            {
                controller.PostTipoDeCanal(tipoDeCanal);
                tipoDeCanal.Nombre = "Edit Unit Test";
                tipoDeCanal.Descripcion = "Unit Test Edit Description";
                response = controller.PutTipoDeCanal(tipoDeCanal.ID, tipoDeCanal);
                ts.Dispose();
            }
            // Assert
            Assert.AreEqual(System.Net.HttpStatusCode.OK,
               response.StatusCode);
        }
        [TestMethod]
        public void DeleteTipoDeCanal()
        {
            TipoDeCanalesController controller = NewController();
            // Act
            TipoDeCanal tipoDeCanal = new TipoDeCanal() { Descripcion = "Unit Test Des", Nombre = "Unit Test" };
            var response = new HttpResponseMessage();
            using (System.Transactions.TransactionScope ts = new System.Transactions.TransactionScope())
            {
                controller.PostTipoDeCanal(tipoDeCanal);
                response = controller.DeleteTipoDeCanal(tipoDeCanal.ID);
                ts.Dispose();
            }
            // Assert
            Assert.AreEqual(System.Net.HttpStatusCode.OK,
               response.StatusCode);
        }
        [TestMethod]
        public void GetTipoDeCanal()
        {
            TipoDeCanalesController controller = NewController();
            // Act
            var tipoCanal = new TipoDeCanal();
            var tipoDeCanal = new TipoDeCanal() { Descripcion = "Unit Test Des", Nombre = "Unit Test" };
            var response = new HttpResponseMessage();
            using (System.Transactions.TransactionScope ts = new System.Transactions.TransactionScope())
            {
                controller.PostTipoDeCanal(tipoDeCanal);
                tipoCanal = controller.GetTipoDeCanal(tipoDeCanal.ID);
                ts.Dispose();
            }
            Assert.IsNotNull(tipoCanal);
        }
        [TestMethod]
        public void GetTiposDeCanal()
        {
            TipoDeCanalesController controller = NewController();
            // Act
            var request = new DataSourceRequest();
            var result = new DataSourceResult();
            var response = new HttpResponseMessage();
            var tipoDeCanal = new TipoDeCanal() { Descripcion = "Unit Test Des", Nombre = "Unit Test" };
            using (System.Transactions.TransactionScope ts = new System.Transactions.TransactionScope())
            {
                controller.PostTipoDeCanal(tipoDeCanal);
                result = controller.GetTiposDeCanal(request);
                ts.Dispose();
            }
            Assert.IsTrue(result.Total >=1);
        }
        private static TipoDeCanalesController NewController()
        {
            TipoDeCanalesController controller = new TipoDeCanalesController();
            controller.Request = new HttpRequestMessage
            {
                RequestUri = new Uri("http://localhost/api/TipoDeCanales")
            };
            controller.Configuration = new HttpConfiguration();
            controller.Configuration.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional });
            controller.RequestContext.RouteData = new HttpRouteData(
                route: new HttpRoute(),
                values: new HttpRouteValueDictionary { { "TipoDeCanalesController", "TipoDeCanal" } });
            return controller;
        }

和 Web API 控制器

public class TipoDeCanalesController : GenericApiController
    {
        private UnitOfWork unitOfWork = new UnitOfWork();
        // GET api/TipoDeCanal/5
        public TipoDeCanal GetTipoDeCanal(int id)
        {
            TipoDeCanal tipoDeCanal = unitOfWork.TipoDeCanalRepository.GetByID(id);
            if (tipoDeCanal == null)
            {
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
            }
            return tipoDeCanal;
        }
        // GET api/TiposDeCanal
        public DataSourceResult GetTiposDeCanal([System.Web.Http.ModelBinding.ModelBinder(typeof(WebApiDataSourceRequestModelBinder))]DataSourceRequest request)
        {
            TipoDeCanal[] tiposDeCanal = unitOfWork.TipoDeCanalRepository.Get().ToArray();
            DataSourceResult result = tiposDeCanal.ToDataSourceResult(request);
            return result;
        }
        // PUT api/TipoDeCanal/            edit
        public HttpResponseMessage PutTipoDeCanal(int id, TipoDeCanal tipoDeCanal)
        {
            if (!ModelState.IsValid)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
            if (id != tipoDeCanal.ID)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
            try
            {
                unitOfWork.TipoDeCanalRepository.Update(tipoDeCanal);
                unitOfWork.Save();
            }
            catch (DbUpdateConcurrencyException ex)
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
            }
            return Request.CreateResponse(HttpStatusCode.OK);
        }
        // POST api/TiposDeCanal   add
        public HttpResponseMessage PostTipoDeCanal(TipoDeCanal tipoDeCanal)
        {
            if (ModelState.IsValid)
            {
                unitOfWork.TipoDeCanalRepository.Insert(tipoDeCanal);
                unitOfWork.Save();
                DataSourceResult result = new DataSourceResult
                {
                    Data = new[] { tipoDeCanal },
                    Total = 1
                };
                HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, result);
                response.Headers.Location = new Uri(Url.Link("DefaultApi", new {Controller="TipoDeCanalesController", id = tipoDeCanal.ID}));
                return response;
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
        }
        // DELETE api/TipoDeCanal/5
        public HttpResponseMessage DeleteTipoDeCanal(int id)
            {
            TipoDeCanal tipoDeCanal= unitOfWork.TipoDeCanalRepository.GetByID(id);
            if (tipoDeCanal == null)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }
            unitOfWork.TipoDeCanalRepository.Delete(tipoDeCanal.ID);           
            try
            {
                unitOfWork.Save();
            }
            catch (DbUpdateConcurrencyException ex)
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
            }
            return Request.CreateResponse(HttpStatusCode.OK, tipoDeCanal);
        }   
        protected override void Dispose(bool disposing)
        {
            unitOfWork.Dispose();
            base.Dispose(disposing);
        }
    }

多语句事务中不允许创建数据库语句.在 TFS 自动生成上

我能够像这样解决它:

  public class TestBase
    {
        private TransactionScope _transactionScope;
        private GenericRepository<TipoDeCanal> _repository;
        private ComisionesContext _dataSource;
        private static bool _isInitialized = false;
        public TestBase()
        {
            if (!_isInitialized)
            {
                TestClassInitialize();
                _isInitialized = true;
            }
        }
        public void TestClassInitialize()
        {
            _repository = new GenericRepository<TipoDeCanal>(ConfigurationManager.ConnectionStrings["ComisionesContext"].ConnectionString);
            _dataSource = new ComisionesContext(ConfigurationManager.ConnectionStrings["ComisionesContext"].ConnectionString);
            _dataSource.Database.Delete();
            _dataSource.Database.CreateIfNotExists();
            _transactionScope = new TransactionScope();
        }
    }

然后在单元测试中

 public class TipoDeCanalesControllerTest : TestBase
    {

        [TestMethod]
        public void PostTipoDeCanal()
        {
            TipoDeCanalesController controller = NewController();
            // Act
            TipoDeCanal tipoDeCanal = new TipoDeCanal() { Descripcion = "Unit Test Des", Nombre = "Unit Test" };
            var response = new HttpResponseMessage();
            using (System.Transactions.TransactionScope ts = new System.Transactions.TransactionScope(TransactionScopeOption.RequiresNew))
            {
                response = controller.PostTipoDeCanal(tipoDeCanal);
                ts.Dispose();
            }
            // Assert
            Assert.AreEqual(System.Net.HttpStatusCode.Created,
               response.StatusCode);
        }