Скорее всего, это связано с тем, что LocalDb не инициализирован на сервере сборки VSO, который запускается для запуска сборки.
Согласно https://github.com/ritterim/automation-sql, LocalDb может быть установлен, но не инициализирован.
LocalDB установлен, но не может подключиться
У вас может быть установлен LocalDB, но вы никогда не инициализировали экземпляр на своем компьютере. Запустите эту команду через командную строку.
Локальная БД SQL EXPRESS 2014
"C:\Program Files\Microsoft SQL Server\120\Tools\Binn\SqlLocalDB.exe" создать "v12.0" 12.0 -s LocalDB SQL Express 2012
"C:\Program Files\Microsoft SQL Server\110\Tools\Binn\SqlLocalDB.exe" create "v11.0" 11.0 -s Убедитесь, что команда работает, используя SQL Server Management Studio для подключения к экземпляру.
Мое решение:
Каждый раз, когда VSO запускает сборку, она создает новую виртуальную машину из шаблона для запуска сборки. В моем случае я хотел динамически создать небольшую базу данных LocalDb, чтобы запускать модульные тесты.
Я использую пакет nuget RimDev.Automation.Sql (http://www.nuget.org/packages/RimDev.Automation.Sql/), чтобы мои тесты могли программно создавать базу данных.
Я также хотел интегрироваться с Unity и Entity Framework 6, чтобы он максимально точно имитировал мой доступ к базе данных в рабочей среде. Для этого я создал базовый класс, от которого наследуются все мои тесты. Я хотел, чтобы все мои тесты использовали одну и ту же базу данных, поэтому я сделал создание LocalDb статическим.
Кроме того, инициализация запускает набор сценариев в папке «Ресурсы», чтобы предварительно заполнить базу данных данными о запасах, если вы того пожелаете. Вам необходимо убедиться, что сценарии sql помечены для копирования в выходную папку (см. свойства), чтобы файлы находились в правильном пути при выполнении модульного теста.
Если вы хотите создать новую базу данных для каждого тестового класса или даже для каждого теста, это можно легко изменить.
using System;
using System.Data.Entity;
using System.IO;
using Microsoft.Practices.Unity;
using Playground.Model;
using RimDev.Automation.Sql;
namespace Playground.UnitTests
{
public abstract class TestBaseClass
{
// For now, these are static. We may want to change them at some point
// to be per class so we create separate databases for each class run, but
// for now, let's not do that for speed sake.
private static readonly IUnityContainer _container = new UnityContainer();
private static bool _isRegistered = false;
private static readonly object _syncRoot = new object();
private static LocalDb LocalDb = new LocalDb(databaseName: "PlaygroundTestDb", databasePrefix: "pg", version: "v12.0");
private static bool _isInitialized = false;
protected TestBaseClass()
{
RegisterComponents(_container);
InitializeData();
_container.BuildUp(GetType(), this);
}
private void InitializeData()
{
lock (_syncRoot)
{
if (!_isInitialized)
{
var dbContext = _container.Resolve<PlaygroundEntities>();
Database.SetInitializer(
new MigrateDatabaseToLatestVersion<PlaygroundEntities, Playground.Model.Migrations.Configuration>());
// Make sure database exists.
dbContext.Database.Initialize(true);
foreach (
var f in Directory.GetFiles(Path.Combine(Environment.CurrentDirectory, "Resources"), "*.sql"))
{
dbContext.Database.ExecuteSqlCommand(File.ReadAllText(f));
}
}
_isInitialized = true;
}
}
private void RegisterComponents(IUnityContainer container)
{
lock (_syncRoot)
{
if (!_isRegistered)
{
// WARNING! Most methods in the unity container are not thread safe. See http://unity.codeplex.com/discussions/27496
// We may need to expose protected methods to register certain types. For now, assume all of the
// tests use the same injected objects. If a test REALLY needs to a different dependency, the test can
// manually create it as well.
container.RegisterType<PlaygroundEntities, PlaygroundEntitiesTest>(new TransientLifetimeManager(),
new InjectionConstructor(new object[] {LocalDb.ConnectionString}));
}
_isRegistered = true;
}
}
}
}
Вот пример теста:
using System.Linq;
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Playground.Model;
namespace Playground.UnitTests
{
[TestClass]
public class UnitTest1 : TestBaseClass
{
[Dependency]
public PlaygroundEntities Db { get; set; }
private static bool _initialized = false;
[TestInitialize]
public void TestInitialize()
{
if (!_initialized)
{
Db.Playgrounds.Add(new Playground.Model.Playground() {Name = "Dave's playground", Location = "SomeTown"});
Db.SaveChanges();
_initialized = true;
}
}
[TestMethod]
public void TestMethod1()
{
var p = Db.Playgrounds.FirstOrDefault(pg => pg.Name == "Dave's playground");
Assert.IsNotNull(p);
}
[TestMethod]
public void TestMethod2()
{
var p = Db.Playgrounds.FirstOrDefault(pg => pg.Location == "SomeTown");
Assert.IsNotNull(p);
}
}
}
Наконец, в моем тестовом проекте у меня есть объект тестовых сущностей.
using Playground.Model;
namespace Playground.UnitTests
{
public class PlaygroundEntitiesTest : PlaygroundEntities
{
private PlaygroundEntitiesTest()
{
}
public PlaygroundEntitiesTest(string connectionString) : base(connectionString)
{
}
}
}
В моем проекте моделей у меня есть моя сущность и мой контекст.
Детская площадка.cs
using System;
namespace Playground.Model
{
public class Playground
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Location { get; set; }
}
}
PlaygroundEntities.cs
using System.Data.Entity;
namespace Playground.Model
{
public class PlaygroundEntities : DbContext
{
public PlaygroundEntities() : base("PlaygroundConnectionString")
{
}
public PlaygroundEntities(string connectionString) : base(connectionString)
{
}
public virtual DbSet<Playground> Playgrounds { get; set; }
}
}
Наконец, я настроил этап после сборки в проекте модульного тестирования, чтобы выполнить команду для инициализации LocalDb следующим образом:
Полная команда
"C:\Program Files\Microsoft SQL Server\120\Tools\Binn\SqlLocalDB.exe" создать "v12.0" 12.0 -s
Затем это было так же просто, как нажать на Visual Studio Online и запустить мою сборку.
![введите здесь описание изображения](https://i.stack.imgur.com/WkzJV.png)
person
Dave Ferguson
schedule
18.03.2015