Если я понимаю правильно, Вы хотите видеть не только классы, но также и методы, свойства и так далее. Единственный инструмент я знаю это, может сделать это, Eclipse - если бы Вы добавляете банку для проектирования пути к классу, Вы были бы в состоянии просмотреть его классы с методами и свойствами с помощью обычного проводника пакетов.
Так или иначе, это - хорошая идея для хорошего автономного инструмента Java
Поскольку вы используете Linq to Sql, вот образец тестирования упомянутого вами сценария с использованием NUnit и Moq. Я не знаю точных деталей вашего DataContext и того, что у вас есть в нем. Отредактируйте под свои нужды.
Вам нужно будет обернуть DataContext специальным классом, вы не можете имитировать DataContext с помощью Moq. Вы также не можете издеваться над SqlException, потому что он запечатан. Вам нужно будет обернуть его своим собственным классом Exception. Выполнить эти две задачи несложно.
Начнем с создания нашего теста:
[Test]
public void FindBy_When_something_goes_wrong_Should_handle_the_CustomSqlException()
{
var mockDataContextWrapper = new Mock<IDataContextWrapper>();
mockDataContextWrapper.Setup(x => x.Table<User>()).Throws<CustomSqlException>();
IUserResository userRespoistory = new UserRepository(mockDataContextWrapper.Object);
// Now, because we have mocked everything and we are using dependency injection.
// When FindBy is called, instead of getting a user, we will get a CustomSqlException
// Now, inside of FindBy, wrap the call to the DataContextWrapper inside a try catch
// and handle the exception, then test that you handled it, like mocking a logger, then passing it into the repository and verifying that logMessage was called
User user = userRepository.FindBy(1);
}
Давайте реализуем тест, сначала давайте обернем наши вызовы Linq в Sql, используя шаблон репозитория:
public interface IUserRepository
{
User FindBy(int id);
}
public class UserRepository : IUserRepository
{
public IDataContextWrapper DataContextWrapper { get; protected set; }
public UserRepository(IDataContextWrapper dataContextWrapper)
{
DataContextWrapper = dataContextWrapper;
}
public User FindBy(int id)
{
return DataContextWrapper.Table<User>().SingleOrDefault(u => u.UserID == id);
}
}
Затем создайте IDataContextWrapper, например Итак, вы можете просмотреть это сообщение в блоге на эту тему, мое немного отличается:
public interface IDataContextWrapper : IDisposable
{
Table<T> Table<T>() where T : class;
}
Затем создайте класс CustomSqlException:
public class CustomSqlException : Exception
{
public CustomSqlException()
{
}
public CustomSqlException(string message, SqlException innerException) : base(message, innerException)
{
}
}
Вот пример реализации IDataContextWrapper:
public class DataContextWrapper<T> : IDataContextWrapper where T : DataContext, new()
{
private readonly T _db;
public DataContextWrapper()
{
var t = typeof(T);
_db = (T)Activator.CreateInstance(t);
}
public DataContextWrapper(string connectionString)
{
var t = typeof(T);
_db = (T)Activator.CreateInstance(t, connectionString);
}
public Table<TableName> Table<TableName>() where TableName : class
{
try
{
return (Table<TableName>) _db.GetTable(typeof (TableName));
}
catch (SqlException exception)
{
// Wrap the SqlException with our custom one
throw new CustomSqlException("Ooops...", exception);
}
}
// IDispoable Members
}
Не уверен, что это помогает, но, похоже, сработало для этого человека (довольно умно).
try
{
SqlCommand cmd =
new SqlCommand("raiserror('Manual SQL exception', 16, 1)",DBConn);
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
string msg = ex.Message; // msg = "Manual SQL exception"
}
Найдено по адресу: http://smartypeeps.blogspot.com/2006/06/how-to-throw-sqlexception-in-c.html
Изменить Ой: Я не понял, что SqlException запечатан. Я издевался над DbException, который является абстрактным классом.
Вы не можете создать новое исключение SqlException, но можете имитировать DbException, от которого происходит SqlException. Попробуйте следующее:
var ex = new Mock<DbException>();
ex.ExpectGet(e => e.Message, "Exception message");
var conn = new Mock<SqlConnection>();
conn.Expect(c => c.Open()).Throws(ex.Object);
Итак, ваше исключение генерируется, когда метод пытается открыть соединение.
Если вы ожидаете прочитать что-либо, кроме свойства Message
в имитируемом исключении, не забудьте Ожидайте (или настройте, в зависимости от вашей версии Moq) «получить» от этих свойств.
Вы можете сделать это с помощью отражения, вам придется поддерживать его, когда Microsoft вносит изменения, но он работает, я только что протестировал его:
public class SqlExceptionCreator
{
private static T Construct<T>(params object[] p)
{
var ctors = typeof(T).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
return (T)ctors.First(ctor => ctor.GetParameters().Length == p.Length).Invoke(p);
}
internal static SqlException NewSqlException(int number = 1)
{
SqlErrorCollection collection = Construct<SqlErrorCollection>();
SqlError error = Construct<SqlError>(number, (byte)2, (byte)3, "server name", "error message", "proc", 100);
typeof(SqlErrorCollection)
.GetMethod("Add", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(collection, new object[] { error });
return typeof(SqlException)
.GetMethod("CreateException", BindingFlags.NonPublic | BindingFlags.Static,
null,
CallingConventions.ExplicitThis,
new[] { typeof(SqlErrorCollection), typeof(string) },
new ParameterModifier[] { })
.Invoke(null, new object[] { collection, "7.0.0" }) as SqlException;
}
}
Это также позволяет вам контролировать количество SqlException, что может быть важным.
Это должно сработать:
SqlConnection bogusConn =
new SqlConnection("Data Source=myServerAddress;Initial
Catalog=myDataBase;User Id=myUsername;Password=myPassword;");
bogusConn.Open();
Это займет немного времени, прежде чем будет сгенерировано исключение, поэтому я думаю, что это сработает еще быстрее:
SqlCommand bogusCommand = new SqlCommand();
bogusCommand.ExecuteScalar();
Код предоставлен вам Hacks-R-Us.
Обновление : нет, второй подход вызывает исключение ArgumentException, а не SqlException.
Обновление 2 : это работает намного быстрее (исключение SqlException возникает менее чем за секунду):
SqlConnection bogusConn = new SqlConnection("Data Source=localhost;Initial
Catalog=myDataBase;User Id=myUsername;Password=myPassword;Connection
Timeout=1");
bogusConn.Open();
(Извините, уже 6 месяцев с опозданием, надеюсь, это не будет считаться некропостингом. Я прилетел сюда, чтобы узнать, как выбросить SqlCeException из имитации).
Если вам просто нужно протестировать код, обрабатывающий исключение, можно сделать очень простой обходной путь:
public void MyDataMethod(){
try
{
myDataContext.SubmitChanges();
}
catch(Exception ex)
{
if(ex is SqlCeException || ex is TestThrowableSqlCeException)
{
// handle ex
}
else
{
throw;
}
}
}
public class TestThrowableSqlCeException{
public TestThrowableSqlCeException(string message){}
// mimic whatever properties you needed from the SqlException:
}
var repo = new Rhino.Mocks.MockReposity();
mockDataContext = repo.StrictMock<IDecoupleDataContext>();
Expect.Call(mockDataContext.SubmitChanges).Throw(new TestThrowableSqlCeException());