Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

Непонятки с EF

3048  1 2 3 4 все
AlexNek патриот25.12.23 20:30
AlexNek
25.12.23 20:30 

Играюсь я тут дома с прогой. НЕТ 8.0

Простой поиск

_dbContext.Users.FirstOrDefault(u => u.Email == email);


Выдаёт непонятную ошибку.

"

Microsoft.Data.SqlClient.SqlException

Invalid column name 'UserId'.

at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)

at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)

...

at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)

at Microsoft.Data.SqlClient.SqlDataReader.TryConsumeMetaData()

at Microsoft.Data.SqlClient.SqlDataReader.get_MetaData()

...

"

При этом юнит тесты с репозиторием и реальной базой работают без проблем. (И с тем же db Context классом)

А вот интеграционный тест выдает уже ошибку, правда сделал на уровень выше с DI и инициализацией базы как в приложении.


Какие будут идеи?

#1 
AlexNek патриот25.12.23 21:15
AlexNek
NEW 25.12.23 21:15 
в ответ AlexNek 25.12.23 20:30

Ошибка исчезает при переименование колонки UserId->Id. UserId это и тип колонки

Ошибка в НЕТ ЕФ?

#2 
Срыв покровов Забанен до 7/7/25 16:05 патриот25.12.23 21:26
NEW 25.12.23 21:26 
в ответ AlexNek 25.12.23 21:15

как называется колонка в БД?

Есть ли для класса User класс конфигурации для EF или конфигурация сделана в виде [Column("Id")]?


#3 
AlexNek патриот25.12.23 21:35
AlexNek
NEW 25.12.23 21:35 
в ответ Срыв покровов 25.12.23 21:26

База генерится так

public sealed class UserConfigurations : IEntityTypeConfiguration<User>
{
    public void Configure(EntityTypeBuilder<User> builder)
    {
        ConfigureUsersTable(builder);
    }
    private void ConfigureUsersTable(EntityTypeBuilder<User> builder)
    {
        builder
            .ToTable("Users");
        builder
            .HasKey(u => u.Id);
        builder
            .Property(u => u.Id)
            //.HasColumnName("UserId")
            .ValueGeneratedNever();
        //.HasConversion(
        //    id => id.Value,
        //    value => UserId.Create(value));
...

С этой строкой не работает .HasColumnName("UserId")

Конверсия сделана глобальной - internal class UserIdConverter : ValueConverter

public sealed class User : AggregateRoot<UserId, Guid>
{
...
    private User(
        UserId id,
#4 
AlexNek патриот25.12.23 21:57
AlexNek
NEW 25.12.23 21:57 
в ответ AlexNek 25.12.23 21:35

Похоже совсем другое. Как заработало, начал данные искать и тут фигвам, они оказались в другой базе. Где как раз имя колонки Id шок

#5 
alex445 коренной житель26.12.23 01:37
NEW 26.12.23 01:37 
в ответ AlexNek 25.12.23 21:57

Т.е. дело оказалось в строке подключения, где указана другая база?

#6 
AlexNek патриот26.12.23 10:53
AlexNek
NEW 26.12.23 10:53 
в ответ alex445 26.12.23 01:37
оказалось в строке подключения, где указана другая база?

в принципе да, но не всё так просто было.

Для запуска в проекте миграции нужен IDesignTimeDbContextFactory со своей строкой подключения в проекте "с базой"

А для запуска приложения используется другая строка подключения, обе строки должны быть идентичны. /Как их брать их одного места пока не придумал смущ/

Поэтому база создавалась в одном месте и юнит тесты дергали ее /для тестов тоже своя строка подключения/, а вот старт приложения или интеграционного теста пользовал другую строку соединения.

#7 
MrSanders коренной житель26.12.23 15:08
NEW 26.12.23 15:08 
в ответ AlexNek 26.12.23 10:53
и юнит тесты дергали ее /для тестов тоже своя строка подключения/,

Глаз зацепился. Как только тест начинает лезть в БД это уже не юнит тест, а интеграционный.

#8 
AlexNek патриот26.12.23 15:31
AlexNek
NEW 26.12.23 15:31 
в ответ MrSanders 26.12.23 15:08
Как только тест начинает лезть в БД это уже не юнит тест, а интеграционный

тут несколько пунктов:

1. Мокать базу смысла не вижу. Обычно база в памяти, не фонтан, но некоторые ошибки можно найти

2. Именно в данном случае, специально использовал реальную базу для дополнительной проверки в чем может быть проблема.

3. Интеграционный тест тоже есть, но он не на уровне репозитория, а "выше"


Хотя сейчас больше интересует другой вопрос как отмапить ссылки на агрегаты по ИД, если ИД - value object



#9 
MrSanders коренной житель26.12.23 17:25
NEW 26.12.23 17:25 
в ответ AlexNek 26.12.23 15:31

Я не говорю, что такие тесты не надо делать. Просто уточнил терминологию. Дверь надо называть дверью. Тест, работающий с базой (даже если в памяти) - не юнит тест, а интеграционный.

#10 
AlexNek патриот26.12.23 17:55
AlexNek
NEW 26.12.23 17:55 
в ответ MrSanders 26.12.23 17:25
Дверь надо называть дверью

По теории вполне возможно. Но если на практике она долгое время называлась дыркой и выглядит как дырка, то никто не захочет называть это дверью смущ Разве в проспекте можно написать - дверь в загадочное подземелье...

Если Moq есть, то нефиг называть энто интеграционным тестом.


ну и напрямую ничего про базы нет, кроме side effect.

"Unit tests focus on a single part of a whole application in total isolation, usually, a single class or function. Ideally, the tested component is free of side effects so it is as easy to isolate and test as possible."

"We have learned that, in practice, the isolation property of unit tests may not be enough for some functions. In this case, one solution is to test how parts of the application work together as a whole. This approach is called integration testing.

Unlike unit testing, integration testing considers side effects from the beginning. These side effects may even be desirable."

#11 
MrSanders коренной житель26.12.23 18:25
NEW 26.12.23 18:25 
в ответ AlexNek 26.12.23 17:55
ну и напрямую ничего про базы нет, кроме side effect.

Мна... Это как? Надо чтобы где-то было написано "юнит тесты не должны использовать базу данных"? И тогда ты поверишь что они действительно это не должны делать?


Не надо искать что-то в "side effects". "...in total isolation, usually, a single class or function".


Если Moq есть, то нефиг называть энто интеграционным тестом.

Неправильно. Во-первых: Mock. Во-вторых: представь, что у тебя три системы (сервиса) А, Б, В. Код из А использует Б и В. Сначала Б, потом В. И ты хочешь проверить интеграцию А с В. Конечно же, ты можешь (и даже должен) замОчить вызов Б. От этого тест не перестал быть интеграционным и стал намного более информативным. Если он сломался - не надо гадать, что у тебя накрылось, Б или В. Ты сразу знаешь что накрылось В.

#12 
AlexNek патриот26.12.23 20:21
AlexNek
NEW 26.12.23 20:21 
в ответ MrSanders 26.12.23 18:25
in total isolation

ладно пойдем от этого... Вот например функция и еще много подобных и посложнее. _dbContext другой класс, значит его нужно чем то заменить. Чем и как?

и как будем после тестировать сам _dbContext? И какой будет толк во всём этом разделении? Не чисто теоретически сервис А и сервис Б, а совершенно практически.

И что изменится если вместо одного названия MyRepo.UnitTest будет другое MyRepo.IntegrationTest? При этом все остальные IntegrationTest используют части "живой системы".

public async Task<Group?> GetMyGroupAsync(UserId ownerId, CancellationToken cancellationToken)
{
    Group? group = await _dbContext.Groups
                       .Include(a => a.Owner)
                       .Include(a => a.Users)
                       .Include(a => a.Information)
                       .FirstOrDefaultAsync(x => x.Owner.Id == ownerId, cancellationToken);
    return group;
}
#13 
MrSanders коренной житель26.12.23 20:40
NEW 26.12.23 20:40 
в ответ AlexNek 26.12.23 20:21, Последний раз изменено 26.12.23 20:41 (MrSanders)

Это очень хороший метод. Для юнит-тестов. Потому что для него юнит-тесты писать не надо. Опа. Он просто "обёртка" вокруг вызова внешней системы. Его надо тестировать интеграционным тестом. Который проверит, что с определённой тестовой БД, в которой есть (например) 10 записей, при поиске с UserId = 123 мы найдём ровно том, что ожидали.


А вот когда мы будем писать юнит-тесты для кода, который вызывает этот метод, мы будем мочить его вызовы. Сможем тестировать код, вызывающий наш гет без БД.

#14 
AlexNek патриот26.12.23 21:55
AlexNek
NEW 26.12.23 21:55 
в ответ MrSanders 26.12.23 20:40
Потому что для него юнит-тесты писать не надо.

Из этого можно сделать вывод, что для всех классов подобного типа не следует писать юнит тесты их просто следует называть интеграционными тестами.

Что меняется от использования другого названия? Тестироваться то будет ОДИН класс, который также написан нами. То есть формально будет юнит тест. Или нужно делать упор на "внешнюю систему", но ведь ее мы не должны тестировать, по умолчанию она работает "правильно".


что с определённой тестовой БД

Этот подход можно пользовать если мы хотим тестировать исключительно Query, а вот с Command будет посложнее, пусть даже база будет в локальном докере.


при поиске с UserId = 123 мы найдём ровно то, что ожидали

Это самое малое что меня будет интересовать в данном случае. А вот загрузится ли полностью владелец или пользователи будет гораздо интереснее.

А если там еще и джойны есть, то есть что проверять.

Статическая база никак не подходит.


А вот когда мы будем писать юнит-тесты для кода, который вызывает этот метод, мы будем мочить его вызовы.

С этим никаких вопросов нет, именно так и делается

#15 
Срыв покровов Забанен до 7/7/25 16:05 патриот26.12.23 22:36
NEW 26.12.23 22:36 
в ответ AlexNek 26.12.23 20:21

нп

А есть какие-то преимущества/недостатки хранения экземпляра dbContext в свойстве класса?

Первое, что приходит на ум, что вот такие вещи будут действовать во всех потоках.

context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.LazyLoadingEnabled = false;
context.Configuration.ProxyCreationEnabled = false;

#16 
AlexNek патриот26.12.23 22:48
AlexNek
NEW 26.12.23 22:48 
в ответ Срыв покровов 26.12.23 22:36
А есть какие-то преимущества/недостатки хранения экземпляра dbContext в свойстве класса?

Что то не припоминаю подобного вопроса. смущ А что предлагаете вместо этого?

public class MyRepository
{
    private readonly MyDbContext _dbContext;
    public MyRepository(MyDbContext dbContext)
    {
        _dbContext = dbContext;
    }
#17 
alex445 коренной житель26.12.23 23:13
NEW 26.12.23 23:13 
в ответ AlexNek 26.12.23 22:48
_dbContext

Подчёркивания - давно дурной тон. Как и всякие префиксы b перед булевыми переменными, e перед перечислениями и т.п. IDE давно всё как надо подсвечивает и выдаёт мгновенные всплывающие подсказки по типам переменных и их принадлежности. Зачем захламлять код закорючками, которые помогали, когда IDE были лишь блокнотами с прикрученными компиляторами?

#18 
AlexNek патриот26.12.23 23:33
AlexNek
NEW 26.12.23 23:33 
в ответ alex445 26.12.23 23:13
Подчёркивания - давно дурной тон.

А вы вот яйца с какого конца разбиваете? ... Неправильно смущ

"this." безусловно лучше, особенно когда смотрю сразу целый экран.

#19 
Срыв покровов Забанен до 7/7/25 16:05 патриот26.12.23 23:57
NEW 26.12.23 23:57 
в ответ AlexNek 26.12.23 22:48

альтернатива это

void DeleteUserById(int id)

{
using (var context = new MyDbContext())

context.Users.Remove(x => x.Id == id);

context.SaveChanges();

}
}

В чем преимущества вашего метода?

#20 
alex445 коренной житель27.12.23 01:21
NEW 27.12.23 01:21 
в ответ AlexNek 26.12.23 23:33, Последний раз изменено 27.12.23 01:31 (alex445)

this нужен лишь в проперти или в конструкторе. Один раз на весь класс. В остальных 10-20 случаях я лучше не буду тянуться до _, тем более, что чтобы в неё попасть, нужно постоянно в неё целиться. Даже если владеешь слепой печатью на английском - всё равно неудобно.

#21 
alex445 коренной житель27.12.23 01:23
NEW 27.12.23 01:23 
в ответ Срыв покровов 26.12.23 23:57

void DeleteUserById(int id)

{
using (var context = new MyDbContext())

context.Users.Remove(x => x.Id == id);

context.SaveChanges();

}

А почему SaveChanges не вызывается автоматически при выходе за пределы контекста MyDbContext? Заставляют писать лишнюю, но очевидную строчку кода.

#22 
alex445 коренной житель27.12.23 01:24
NEW 27.12.23 01:24 
в ответ Срыв покровов 26.12.23 23:57, Последний раз изменено 27.12.23 01:34 (alex445)
using (var context = new MyDbContext())
using (MyDbContext context = new())

Второй вариант лучше. В первом варианте var не несёт никакого смысла и просто семантический мусор. Я бы на месте создателей Шарпа позволил бы в таких конструкциях вообще не писать ничего перед context.

#23 
alex445 коренной житель27.12.23 01:28
NEW 27.12.23 01:28 
в ответ Срыв покровов 26.12.23 23:57, Последний раз изменено 27.12.23 01:35 (alex445)
public class MyRepository
{
    private readonly MyDbContext _dbContext;
    public MyRepository(MyDbContext dbContext)
    {
        _dbContext = dbContext;
    }
void DeleteUserById(int id)
{
using (var context = new MyDbContext())
context.Users.Remove(x => x.Id == id);
context.SaveChanges();
}

Когда я пишу свою репу, т.к. у меня нет БД и всё в файлах - это понятно, зачем мне своя репа. Когда вы тупо переписываете все функции EF, а потом ещё и юнит-тестируете их, вы просто душнилы. ))

#24 
Срыв покровов Забанен до 7/7/25 16:05 патриот27.12.23 08:28
NEW 27.12.23 08:28 
в ответ alex445 27.12.23 01:23
А почему SaveChanges не вызывается автоматически при выходе за пределы контекста MyDbContext?

Ну например потому что ты из контекста мог только выбирать данные (select).

#25 
Срыв покровов Забанен до 7/7/25 16:05 патриот27.12.23 08:31
NEW 27.12.23 08:31 
в ответ alex445 27.12.23 01:28

Душнила 2 года подряд ноет на автофоруме, что для него не сделали подхядящий электрический автобус.

#26 
alex445 коренной житель27.12.23 09:59
NEW 27.12.23 09:59 
в ответ Срыв покровов 27.12.23 08:28, Последний раз изменено 27.12.23 10:05 (alex445)
Ну например потому что ты из контекста мог только выбирать данные (select).

Не в этом суть. То, что в контексте лишь выборка идёт, сам контекст прекрасно знает. Почему бы ему внутри себя не вызывать автоматом сохранение изменений при выходе за пределы контекста, если там кроме выборки ещё что-то изменилось? Ведь подавляющая часть сценариев - создали контекст, что-то сделали, сохранили изменения, вышли за предел. И все эти рутинные обязательные вызовы можно делать внутри себя.


Вот почему-то от ручного вызова Dispose каждый раз они нас избавили, от сохранения контекста - нет. Короче, там ещё улучшать и улучшать. Сишарп страдает от того, что слишком быстро идёт вперёд, но старьё не чистит. В результате в языке много мусора, в том числе синтаксического. По-моему, было бы неплохо в какой-нибудь версии отменить обратную совместимость. Эта совместимость по большому счёту не нужна. Например, на моём проекте хоть и новый код и новые проекты в солюшене пишутся на новых версиях дотнета, но главный программист запрещает использовать подавляющее число нововведений из языка - чтобы консистентность со старым кодом (из времён .NET Framework 3.x, 4.x) сохранялась. Там же это, как его - догматы, что код должен по всему проекту быть по-возможности одинаковым. Я им, что с таким подходом этот проект будет вечно старьём, которое будет просто переводиться на новые рельсы (.NET 5, 6,...), но их возможности не исползовать. Там, где я на 3-5 строк пишу реализацию свойства по-новому, он расписывает на пол экрана в максимально старом стиле. Убивает читаемость кода в угоду глупой преемственности.


Кстати, новички, пришедшие на такой проект и обучавшиеся на новых версиях языка, скорее старый код меньше понимать будут, чем новый. Им будет просто непонятен смысл многословных простыней и кучи вложенных скобок там, где уже давно от этого можно было бы избавиться. Тут какой-то скрытый смысл умудрённых опытом мегасеньёров? - Нет, просто старпёры задеревенели и не хотят учить новое.

#27 
alex445 коренной житель27.12.23 10:02
NEW 27.12.23 10:02 
в ответ Срыв покровов 27.12.23 08:31
Душнила 2 года подряд ноет на автофоруме, что для него не сделали подхядящий электрический автобус.

Ещё недавно же каблучок был?


Автобус всяко лучше утыканной сверху и сзади всякими грузовыми обвесами "малолитражки".

#28 
Срыв покровов Забанен до 7/7/25 16:05 патриот27.12.23 10:59
NEW 27.12.23 10:59 
в ответ alex445 27.12.23 09:59
И все эти рутинные обязательные вызовы можно делать внутри себя.

мне, имеющему опыт с SQL, логично в конце всех операций сделать Commit SaveChanges()

Тебе же никто не запрещает переписать Dispose твоего контекста

Там, где я на 3-5 строк пишу реализацию свойства по-новому, он расписывает на пол экрана в максимально старом стиле.

Можно пример?

#29 
Срыв покровов Забанен до 7/7/25 16:05 патриот27.12.23 11:04
NEW 27.12.23 11:04 
в ответ alex445 27.12.23 10:02
Ещё недавно же каблучок был?

Так ты же сначала именно про них и пел

Автобус всяко лучше утыканной сверху и сзади всякими грузовыми обвесами "малолитражки".

у меня так-то двухлитровый дизель

Обвес это 5 раз в год - крепление для велосипедов сзади.
А стальные 360 дней красивый компактный комфортный быстрый автомобиль

#30 
alex445 коренной житель27.12.23 11:12
NEW 27.12.23 11:12 
в ответ Срыв покровов 27.12.23 11:04

Куда спешить со всей семьёй? Я еду 120+- и мне хватает. Тем более, что на большинстве мест, особенно на австрийских и итальянских автобанах, больше 130 не разрешено.


А у меня "обвес" это каждые выходные с мая по сентябрь, плюс отпуска. В малолитражку внутрь он не лезет, и сзади не цепляется.

#31 
alex445 коренной житель27.12.23 11:23
NEW 27.12.23 11:23 
в ответ Срыв покровов 27.12.23 10:59, Последний раз изменено 27.12.23 11:31 (alex445)
Тебе же никто не запрещает переписать Dispose твоего контекста

Мне никто не мешает хоть весь .NET переписать. Но ценится больше то, что хорошо работает из коробки.


Можно пример?

Я приводил уже. Сейчас все проекты закрыты, поэтому по-памяти примерно так:


его вариант

private MyType myObject;
public MyType MyObject
{
    get
    {
        if(myObject == null)
        {
            myObject = new MyType();
        }
        инициализация myObject
        return myObject;
    }
}


мой вариант

MyType myObject;
public MyType MyObject => myObject ??= new()
{
    инициализация myObject
}
#32 
alex445 коренной житель27.12.23 11:27
NEW 27.12.23 11:27 
в ответ alex445 27.12.23 11:23, Последний раз изменено 27.12.23 11:28 (alex445)

Или вот он говорит, чтобы я using обязательно использовал в старом стиле со скобочками (явное обозначение контекста), хотя без них всё проще и короче. И ещё несколько подобных моментов, которые вроде бы мелочь, но бесит, когда понимаешь, что можно проще, но нужно повторять шаг в шаг за дедками. А потому что в старых (15-летней давности) кусках кода так использовалось. Т.е. проект 15-летней давности нужно и через 10 лет от сегодняшнего дня писать как проект уже 25-летней давности. А то неконсистентно. То, что новый прогер, пришедший на проект, такую древность может уже и не понять - это консистентно.

#33 
AlexNek патриот27.12.23 12:01
AlexNek
NEW 27.12.23 12:01 
в ответ alex445 27.12.23 01:21
я лучше не буду тянуться до _

Не вижу никаких, проблем - всё на автомате.

Но дискутировать по поводу code style смысла особого не имеет, у каждой команды свои соглашения и хотя не все с ними согласны, нужно делать как договорились.


#34 
MrSanders коренной житель27.12.23 12:03
NEW 27.12.23 12:03 
в ответ AlexNek 26.12.23 21:55
Из этого можно сделать вывод, что для всех классов подобного типа не следует писать юнит тесты их просто следует называть интеграционными тестами.

1. Мы не про класс а про метод. Про конкретный метод. Из этого одного примера не надо делать далекоидущие выводы для каких-то "классов подобного типа".

2. Кого "их" называть? Тесты, которым для работы нужна БД? Да, их просто следует называть интеграционными.

Этот подход можно пользовать если мы хотим тестировать исключительно Query, а вот с Command будет посложнее, пусть даже база будет в локальном докере.
...

Это самое малое что меня будет интересовать в данном случае. А вот загрузится ли полностью владелец или пользователи будет гораздо интереснее.

А если там еще и джойны есть, то есть что проверять.

Статическая база никак не подходит.

Это всё абсолютно не важно. Прилепил базу - прекращай называть тест "юнит-тестом". Ничего больше. Что сложного-то? А в своем интеграционном тесте можешь тестировать хоть джойны в докере, хоть простенькие селекты в in-memory.


#35 
AlexNek патриот27.12.23 12:04
AlexNek
NEW 27.12.23 12:04 
в ответ alex445 27.12.23 01:24
using (var context = new MyDbContext())
using (MyDbContext context = new())

>Второй вариант лучше

Можно спорить до потери сознания и каждый останется при своем мнении.

Когда-то удобен var, когда то нет. В данном случае, мне больше нравится 1й.

#36 
AlexNek патриот27.12.23 12:11
AlexNek
NEW 27.12.23 12:11 
в ответ alex445 27.12.23 09:59
По-моему, было бы неплохо в какой-нибудь версии отменить обратную совместимость.

Вот класс, открываешь старый проект, а он вчера компилился, а сегодня уже нет.


Нет, просто старпёры задеревенели и не хотят учить ново

А вот не старпёр уже вовсю пользует primary constructor или всё же нет?

#37 
AlexNek патриот27.12.23 12:25
AlexNek
NEW 27.12.23 12:25 
в ответ Срыв покровов 26.12.23 23:57
В чем преимущества вашего метода?

Метод не мой, всего лишь рекомендация руководящей партии - DbContext in dependency injection for ASP.NET Core

https://learn.microsoft.com/en-us/ef/core/dbcontext-config...


"It is generally better to inject the database context (MyDbContext) through the constructor rather than instantiating it directly within each method call. This approach follows the principle of dependency injection and allows for better testability and flexibility."


А приведенный вариант не очень гибкий как в вопросах тестирования, так и для модификации.

А если время жизни контекста и репозитория совпадают со временем жизни запроса, то отличий в функциональности пока не вижу.

#38 
alex445 коренной житель27.12.23 12:27
NEW 27.12.23 12:27 
в ответ AlexNek 27.12.23 12:04
Когда-то удобен var, когда то нет. В данном случае, мне больше нравится 1й.

Тут не удобство, а элементарная логика. Если с правой стороны объявлен тип, то с левой писать его ещё раз не имеет смысла. Ну кроме случаев полиморфизма. Но дать возможность не писать лишнее слово там, где это не нужно - нужно.

#39 
alex445 коренной житель27.12.23 12:33
NEW 27.12.23 12:33 
в ответ AlexNek 27.12.23 12:11
По-моему, было бы неплохо в какой-нибудь версии отменить обратную совместимость.

Вот класс, открываешь старый проект, а он вчера компилился, а сегодня уже нет.

Для этого есть необратимые конвертеры старого в новое. Куча программ так и работает - либо конвертим в новое, либо сидим на старой версии. Тот же Unity, многие пакеты 3D (и не только) моделирования. Да и сами языки некоторые идут по таким стопам. Вроде, Питон в каких-то версиях не совместим. Потом из мира веба - Ангуляр. У Яблока это вообще возведено в принцип работы - как с пользователями, так и с разработчиками (Swift).


Это лучше, чем копить мусор в языке. Если копить, рано или поздно придётся его похоронить. Или таки выпустить версию без совместимости и "начать с чистого листа".

#40 
alex445 коренной житель27.12.23 12:35
NEW 27.12.23 12:35 
в ответ AlexNek 27.12.23 12:11
А вот не старпёр уже вовсю пользует primary constructor или всё же нет?

Я пока нет. Но если встретится подходящее место, где он будет удобен - буду.

#41 
AlexNek патриот27.12.23 12:36
AlexNek
NEW 27.12.23 12:36 
в ответ MrSanders 27.12.23 12:03
Прилепил базу - прекращай называть тест "юнит-тестом"

Как будет подобное соглашение в команде, можно и переназвать. Но пока не вижу особого смысла в смене названия.


Про конкретный метод

Все методы в классе практически одинаковые _dbContext.xxxx;


Что сложного-то?

То что уже есть группа интеграционных тестов и эта группа придерживается другой классификации.

#42 
AlexNek патриот27.12.23 12:43
AlexNek
NEW 27.12.23 12:43 
в ответ alex445 27.12.23 12:27
Если с правой стороны объявлен тип, то с левой писать его ещё раз не имеет смысла. Ну кроме случаев...

ну вот именно, что кроме случаев...

И в какой-то стороне обязательно нужно.


Но дать возможность не писать лишнее слово там, где это не нужно - нужно.

если имеемся в виду убрать var? Не думаю что это просто с точки зрения компилятора, да и большой бардак получается при этом.

#43 
AlexNek патриот27.12.23 12:49
AlexNek
NEW 27.12.23 12:49 
в ответ alex445 27.12.23 12:33
Для этого есть необратимые конвертеры старого в новое.

Эти все рассуждения хороши пока нет тонн старого кода.

Кто даст 100% гарантию того, что после конвертации всё будет работать как и раньше?

Как минимум, нужно проводить дополнительное тестирование. А на это времени просто нет.

#44 
AlexNek патриот27.12.23 13:01
AlexNek
NEW 27.12.23 13:01 
в ответ alex445 27.12.23 12:35
Я пока нет.

ну вот именно, как будут подходящие условия...

Дело то не в том знаешь или нет, а в том есть ли условия для этого.

Вот если такого мужика весной или осенью увидишь, что можно сказать?


#45 
MrSanders коренной житель27.12.23 13:18
NEW 27.12.23 13:18 
в ответ AlexNek 27.12.23 12:36
Как будет подобное соглашение в команде, можно и переназвать. Но пока не вижу особого смысла в смене названия.

Дааа... "И эти люди запрещают мне ковырятся в носу" (с)

Может намекнуть команде, что назвать вещи надо так, как они называются? Ну, чисто по приколу. Чтобы вас понимать было можно.


P.S. А потом ходят такие "командные" и рассказывают о юнит-тестах, которые они не пишут, потому что они очень долго выполняются. А ты сидишь и гадаешь что же он имел в виду?

#46 
AlexNek патриот27.12.23 14:20
AlexNek
NEW 27.12.23 14:20 
в ответ MrSanders 27.12.23 13:18
Может намекнуть команде, что назвать вещи надо так, как они называются?

Пока, что все согласны с тем как всё называется смущ

https://www.bitiniyan.com/2019/02/02/how-to-write-unit-tes...


И ковыряйтесь в носу, сколько душе угодно. И мы будем в своем тоже ковыряться. Главное, чтобы не увидели как мы это делаем вместе спок


Значит если базу мОкаем - эту юнит тест, а если нет, то уже интеграционный - так?


Чтобы вас понимать было можно.

Проблем с пониманием пока не было, а вот если переименуем то точно появятся.

#47 
alex445 коренной житель27.12.23 14:43
NEW 27.12.23 14:43 
в ответ AlexNek 27.12.23 12:43, Последний раз изменено 27.12.23 14:44 (alex445)
если имеемся в виду убрать var? Не думаю что это просто с точки зрения компилятора, да и большой бардак получается при этом.

Проблемы разработки компилятора меня не волнуют - я пользователь.


Какой бардак? Вам трёх попыток хватит, чтобы угадать, какой тип у myVariable?


myVariable = new MyType();

или

MyType myVariable = new();


Заметьте, что сейчас второй вариант полностью валидный. Но это зеркально первому. А первый - не валидный.

#48 
alex445 коренной житель27.12.23 14:47
NEW 27.12.23 14:47 
в ответ AlexNek 27.12.23 12:49

Кто даст 100% гарантию того, что после конвертации всё будет работать как и раньше?

Как минимум, нужно проводить дополнительное тестирование. А на это времени просто нет.

Если у вас не проект-однодневка, то вам в любом случае когда-то придётся всё конвертировать, переходить, тестировать. И лучше делать это, когда нового накопилось не так много, чем через 10-15 лет.

#49 
alex445 коренной житель27.12.23 14:49
NEW 27.12.23 14:49 
в ответ AlexNek 27.12.23 13:01, Последний раз изменено 27.12.23 14:50 (alex445)
Вот если такого мужика весной или осенью увидишь, что можно сказать?

"Мистер Сандерс, не узнаю вас в гриме!"

))

#50 
MrSanders коренной житель27.12.23 14:53
NEW 27.12.23 14:53 
в ответ AlexNek 27.12.23 14:20, Последний раз изменено 27.12.23 14:55 (MrSanders)
Пока, что все согласны с тем как всё называется смущ

Да пожалста. Хоть горшком называйте. Только не удивляйся что за пределами команды тебя понимать не будут.

Значит если базу мОкаем - эту юнит тест, а если нет, то уже интеграционный - так?

Где-то так, да.

На всякий случай (а то тут такие вопросы всплвали, а где конкретно про БД написано...): это не значит что если мы заменили доступ к базе моком, а к (например) LDAP оставили как есть, то такой тест можно называть юнит-тестом. (а чо, "если базу мОкаем - юнит тест", а про LDAP не написано нигде!)

#51 
AlexNek патриот27.12.23 16:45
AlexNek
NEW 27.12.23 16:45 
в ответ alex445 27.12.23 14:43
Проблемы разработки компилятора меня не волнуют - я пользователь.

Хочу бусик, чтобы за секунды доставлял меня до моря.

Проблемы разработчиков авто меня не волнуют - я пользователь. спок


чтобы угадать, какой тип у myVariable

Мне не нужно гадать, я хочу увидеть и знать

#52 
AlexNek патриот27.12.23 16:51
AlexNek
NEW 27.12.23 16:51 
в ответ alex445 27.12.23 14:47
Если у вас не проект-однодневка, то вам в любом случае когда-то придётся всё конвертировать, переходить, тестировать.

Как раз наоборот. Если проекту много лет, то его ни в коем случае нельзя трогать. Любые изменения только в крайнем случае.

Если есть бюджет, то лучше начать с нуля.

#53 
AlexNek патриот27.12.23 16:55
AlexNek
NEW 27.12.23 16:55 
в ответ MrSanders 27.12.23 14:53
Только не удивляйся что за пределами команды тебя понимать не будут.

Скорее наоборот. Мне нужно некое определение и так как Вы его интерпретируете я пока не нахожу смущ Скорее - A more important distinction is whether the unit you're testing should be sociable or solitary

https://martinfowler.com/testing/


#54 
alex445 коренной житель27.12.23 20:53
NEW 27.12.23 20:53 
в ответ AlexNek 27.12.23 16:45

Хочу бусик, чтобы за секунды доставлял меня до моря.

Проблемы разработчиков авто меня не волнуют - я пользователь. спок

Нормальная инфраструктура зарядок, и запас хода не как у скутера-переростка. То, что сейчас - издевательство над покупателем.

#55 
alex445 коренной житель27.12.23 20:54
NEW 27.12.23 20:54 
в ответ AlexNek 27.12.23 16:45
чтобы угадать, какой тип у myVariable

Мне не нужно гадать, я хочу увидеть и знать

В том-то и дело, что по обеим моим записям увидел и всё понял.

#56 
alex445 коренной житель27.12.23 20:57
NEW 27.12.23 20:57 
в ответ AlexNek 27.12.23 12:01

у каждой команды свои соглашения и хотя не все с ними согласны, нужно делать как договорились.

Ну вот я и делаю, хотя и не согласен.

#57 
MrSanders коренной житель27.12.23 21:14
NEW 27.12.23 21:14 
в ответ AlexNek 27.12.23 16:55

Фаулер остался в 90-х. Ну, в начале 2000-х. Почему-то. Когда то, что он называет "sociable" было единственным способом. Изолировать тестируемый "юнит" было можно. Но на это уходило немало времени. А с фреймворками для моков ему было уже лень разбираться. Да и не работал он уже. За прошедшие с тех пор почти 30 лет, люди поняли что чем изолированней, тем для юнит тестов лучше (а вообще и для всех, кроме end-to-end или nfr-тестов вроде нагрузочных). Увидели что легко изолируемый код ещё и легче расширять, чем неизолируемый. Придумали FIRST. А определение... В индустрии программирования с этим вообще-то большие проблемы. Ни IETF RFC, ни ISO нормы для юнит-тестов нет. ISTQB ими не заморачивается, это дело программистов. Так что только мнения и опыт.


#58 
AlexNek патриот27.12.23 22:15
AlexNek
NEW 27.12.23 22:15 
в ответ alex445 27.12.23 20:53
Нормальная инфраструктура зарядок

Вообще-то было совсем про другое, а пример чтобы было просто более понятно.


То, что сейчас - издевательство над покупателем.

А это как тогда назвать?


#59 
AlexNek патриот27.12.23 22:18
AlexNek
NEW 27.12.23 22:18 
в ответ alex445 27.12.23 20:54
что по обеим моим записям увидел и всё понял.

А хотя бы так? Тоже всё понятно?

myVariable = new MyType();

...

myVariable = new MyType2();

...

myVariable = new MyType2() + new MyType2();



#60 
AlexNek патриот27.12.23 22:22
AlexNek
NEW 27.12.23 22:22 
в ответ MrSanders 27.12.23 21:14
Фаулер остался в 90-х.

А кто тогда не остался?


Так что только мнения и опыт.

Согласен, вот и хочу насобирать мнения для начала.

#61 
Срыв покровов Забанен до 7/7/25 16:05 патриот28.12.23 00:18
NEW 28.12.23 00:18 
в ответ alex445 27.12.23 11:27
Или вот он говорит, чтобы я using обязательно использовал в старом стиле со скобочками (явное обозначение контекста), хотя без них всё проще и короче.

Как раз в случае с контекстом я хочу видеть момент его контекста

Но это таким модным молодежным не понять.

#62 
Срыв покровов Забанен до 7/7/25 16:05 патриот28.12.23 00:24
NEW 28.12.23 00:24 
в ответ alex445 27.12.23 11:23

Ну сэкономил 5 сток, какой молодец. А что при чтении твоего когда взрывается моск, пофиг)

И вообще, почему не так?


private MyType myObject = new MyType()
{
    инициализация myObject
};
public MyType MyObject => myObject;
#63 
Срыв покровов Забанен до 7/7/25 16:05 патриот28.12.23 00:31
NEW 28.12.23 00:31 
в ответ alex445 27.12.23 12:27
Если с правой стороны объявлен тип, то с левой писать его ещё раз не имеет смысла

поэтому его никто и не пишет, а ограничиваются словом var, Карл.

#64 
alex445 коренной житель28.12.23 01:42
NEW 28.12.23 01:42 
в ответ Срыв покровов 28.12.23 00:31
Если с правой стороны объявлен тип, то с левой писать его ещё раз не имеет смысла

поэтому его никто и не пишет, а ограничиваются словом var, Карл.

А без слова можно?

#65 
alex445 коренной житель28.12.23 01:45
NEW 28.12.23 01:45 
в ответ Срыв покровов 28.12.23 00:24, Последний раз изменено 28.12.23 01:51 (alex445)


private MyType myObject = new MyType()
{
    инициализация myObject
};
public MyType MyObject => myObject;

Можно и так. По мне, так даже для онли геттеров нужно сделать поддерживающее поле по-умолчанию. Отдельное явное объявление поля - просто лишний код. Если нужно его как-то особенно реализовать - делаешь сам. А если стандарт - пусть будет автоматическое по-умолчанию. Т.е. что-то типа такого или такого


public MyType MyObject => ??= new()
{
    инициализация myObject
}
public MyType MyObject ??= new()
{
    инициализация myObject
}


#66 
Срыв покровов Забанен до 7/7/25 16:05 патриот28.12.23 08:40
NEW 28.12.23 08:40 
в ответ alex445 28.12.23 01:42
А без слова можно?

в яваскрипте все можно

#67 
1 2 3 4 все