Testing this command - wpf

I'm quite new to unit tests and I've got some troubles testing this command
internal async Task OnDeleteTreasurerCommandExecute(TesorieraItemResult tesoriera)
{
try
{
if (await MessageService.ShowAsync("Confermare l'operazione?", string.Empty, MessageButton.YesNo, MessageImage.Question) == MessageResult.Yes)
{
await repository.DeleteTesorieraItemAsync(tesoriera.ID_ISTITUTO,tesoriera.ID_DIVISA,tesoriera.PROGRESSIVO);
await MessageService.ShowInformationAsync("Operazione completata");
if (SelectedInstitute != null)
await OnLoadDataCommandExecute();
}
}
catch (Exception ex)
{
ErrorService.HandleError(GetType(), ex);
}
}
I'm using Catel as MVVM framework
how do I simulate the yes/no answers?
Thanks

You need to substitute the MessageService with a class that can return yes or no answer. Here's an example using NSubstitute.
Install-Package NSubstitute
Install-Package NUnit
Let us say you have a class that has a method that
needs Yes, then No:
public class AccountViewModel
{
readonly IMessageService _messageService;
readonly ICustomerRepository _customerRepository;
public AccountViewModel(IMessageService messageService, ICustomerRepository customerRepository)
{
_messageService = messageService;
_customerRepository = customerRepository;
}
public async Task OnDeleteCustomer(Customer customer)
{
if (await MessageService.ShowAsync(
"Confirm?",
string.Empty,
MessageButton.YesNo,
MessageImage.Question) == MessageResult.Yes)
{
_customerRepository.Delete(customer);
await MessageService.ShowInformationAsync("Completed");
}
}
}
Then your test case looks like this:
public class TestAccountViewModel
{
[TestCase]
public class TestDeleteCustomer()
{
// arrange
var messageService = Substitute.For<IMessageService>();
messageService
.ShowAsync(
Arg.Any<string>(),
Arg.Any<string>(),
Arg.Any<MessageButton>(),
Arg.Any<MessageImage>())
.Returns(Task.FromResult(MessageResult.Yes);
messageService
.ShowInformationAsync(Arg.Any<string>())
.Returns(Task.FromResult<object>(null));
var customerRepository = Substitute.For<ICustomerRepository>();
// act
var sut = new AccountViewModel(messageService, customerRepository);
var customer = new Customer();
sut.OnDeleteCustomer(customer);
// assert
Assert.IsTrue(customerRepository.Received().DeleteCustomer(customer));
}
}

In a past version, Catel provided a test implementation of the IMessageService that allowed you to queue expected results so you could test the different paths inside a command.
I just noticed this class is no longer available, but you can easily implement a test stub yourself (using mocking, etc). Or you could contribute to Catel and revive the test implementation.

Related

ABPFramwork - Remove api from layer application in swagger

I have created a project using abpframwork. When running swagger, swagger receives the function in the application layer is a api. I don't want that. Can you guys tell me how to remove it in swagger
Code in Application Layer
public class UserService : AdminSSOAppService, ITransientDependency, IValidationEnabled, IUserService
{
IUserRepository _userRepository;
private readonly ILogger<UserService> _log;
public UserService(IUserRepository userRepository,
ILogger<UserService> log
)
{
_userRepository = userRepository;
_log = log;
}
public async Task<List<UserDto>> GetList()
{
var list = await _userRepository.GetListAsync();
return ObjectMapper.Map<List<User>, List<UserDto>>(list);
}
public async Task<UserDto> GetUserById(int Id)
{
var user = await _userRepository.GetAsync(c=>c.Id == Id);
return ObjectMapper.Map<User, UserDto>(user);
}
}
Code in HttpApi Layer
[Area(AdminSSORemoteServiceConsts.ModuleName)]
[RemoteService(Name = AdminSSORemoteServiceConsts.RemoteServiceName)]
[Route("api/user/user-profile")]
public class UserController : ControllerBase, IUserService
{
private readonly IUserService _userAppService;
public UserController(IUserService userAppService)
{
_userAppService = userAppService;
}
[HttpGet]
[Route("get-list-httpapi")]
public Task<List<UserDto>> GetList()
{
return _userAppService.GetList();
}
[HttpGet]
[Route("get-by-id-httpapi")]
public Task<UserDto> GetUserById(int Id)
{
return _userAppService.GetUserById(Id);
}
}
I can suggest a workaround as to enable only the APIs you need to appear on swagger (though the ones that don't appear anymore will still be available for consumption).
I would suggest you add a configuration part in your *.Http.Api project module inside your ConfigureSwaggerServices, like so:
context.Services.AddSwaggerGen(options =>
{
options.DocInclusionPredicate(
(_, apiDesc) =>
apiDesc
.CustomAttributes()
.OfType<IncludeInSwaggerDocAttribute>()
.Any());
});
And for the attribute, it would be very simple, like so:
[AttributeUsage(AttributeTargets.Class)]
public class IncludeInSwaggerDocAttribute : Attribute
{
}
This will let you achieve what you want, however I still recommend reading the doc carefully to be able to implement DDD.

Problems running multiple xunit tests under STA Thread WPF

Following on from my experimentation with xunit wpf tests I have hit an issue when running multiple tests.
The issue is when I am checking Application.Current.Windows in my assertions.
The Code
To replicate the following code will cause the issue:
TestWindow
<Window x:Class="acme.foonav.Issues.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:acme.foonav.Issues"
mc:Ignorable="d"
Title="TestWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
Test
public class WpfFactIssues
{
public WpfFactIssues()
{
if (Application.Current == null)
{
new Application();
}
}
[WpfFact]
public void Test1()
{
TestWindow window = new TestWindow();
Assert.Equal(typeof(TestWindow), Application.Current.Windows[0]?.GetType());
}
[WpfFact]
public void Test2()
{
TestWindow window = new TestWindow();
Assert.Equal(typeof(TestWindow), Application.Current.Windows[0]?.GetType());
}
}
So here, Test1 and Test2 are identical. I have removed any other logic not required to demonstrate this scenario to focus on the actual issue - and not why would I want to do this!
The purpose of the scenario was to check whether a window was added into the current application's window collection.
We are using Xunit.StaFact to manage running on the STA Thread.
The Issue
If I execute ALL tests (in Rider) then Test1 will pass, and Test2 will fail on the assertion.
System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.
However, I can successfully execute Test1 and Test2 individually.
When executing, Test1 will run on say thread id (Thread.CurrentThread.ManagedThreadId) of 20 then Test2 will execute on.
When Test2 executes, then Application.Current is set to what Test1 setup.
What I have tried
Implementing IDisposable and trying calling Application.Current?.Shutdown() in the desperate attempt to make it work.
public void Dispose()
{
if (Application.Current != null)
{
ManualResetEventSlim manualResetEvent = new ManualResetEventSlim(false);
Application.Current.Exit += (sender, args) => { manualResetEvent.Set(); };
Application.Current?.Shutdown();
manualResetEvent.Wait(TimeSpan.FromSeconds(5));
}
}
Here the Exit event is never raised.
This will throw a different exception:
System.InvalidOperationException: Cannot create more than one System.Windows.Application instance in the same AppDomain.
Help!
Is there a way to work with the Application in unit tests when executing lots of methods in the same class?
Update
Currently looking at:
Manage Application.Current while all tests are running in Test Project
I'll post this on here for now, although it solves the issue, it yields a further issue.
If we implement a dispose pattern on the test class, we can force a shutdown of the application. This is somewhat slightly crude.
public void Dispose()
{
if (Application.Current != null)
{
Application.Current.Shutdown(0);
var result = Application.Current.Dispatcher.InvokeAsync(() => { }, DispatcherPriority.ContextIdle).Result;
}
}
However, when the second test runs, the following exception will be thrown:
System.InvalidOperationException: Cannot create more than one System.Windows.Application instance in the same AppDomain.
Don't try this at home!
So lets have some hacky fun with reflection around the internals of Application - to make this work - at least for this scenario:
Let's track our test state around the Application:
public static class FooYou
{
public static bool hasInited = false;
}
This all becomes clear when we new up the Application in our test constructor:
public WpfFactIssues()
{
if (Application.Current == null)
{
new Application()
{
ShutdownMode = ShutdownMode.OnExplicitShutdown
};
if (!FooYou.hasInited)
{
FooYou.hasInited = true;
}
else
{
var appInit = typeof(Application).GetMethod("ApplicationInit", BindingFlags.Static | BindingFlags.NonPublic);
appInit.Invoke(null, null);
}
}
}
One final change in the dispose implementation - pretend the app wasn't created in this app domain otherwise this causes the Cannot create more than one System.Windows.Application instance in the same AppDomain exception.
public void Dispose()
{
if (Application.Current != null)
{
Application.Current.Resources.MergedDictionaries.Clear();
Application.Current.Shutdown(0);
var result = Application.Current.Dispatcher.InvokeAsync(() => { }, DispatcherPriority.ContextIdle).Result;
var appCreated = typeof(Application).GetField("_appCreatedInThisAppDomain",
BindingFlags.Static |
BindingFlags.NonPublic);
appCreated.SetValue(null, false);
}
}
Here we are forcing the reinit of the Application - as done by the Application's static initializer.
Of course, this is a hideous abomination of a solution. It's dirty. It is of course very susceptible to breaking - never touch a classes privates.
A more workable application of helpers
The above is a little crude, so wrapping up to make the tests work without much effort:
using System.Reflection;
using System.Windows;
using System.Windows.Threading;
namespace acme.foonav.Fixture
{
public static class ApplicationState
{
private static bool hasApplicationPreviouslyInitialized;
public static void CreateNew()
{
Shutdown();
if (Application.Current == null)
{
new Application()
{
ShutdownMode = ShutdownMode.OnExplicitShutdown
};
if (!hasApplicationPreviouslyInitialized)
{
hasApplicationPreviouslyInitialized = true;
}
else
{
var pre = typeof(Application);
var clear = pre.GetMethod("ApplicationInit", BindingFlags.Static | BindingFlags.NonPublic);
clear.Invoke(null, null);
}
}
}
public static void Shutdown()
{
if (Application.Current != null)
{
Application.Current.Resources.MergedDictionaries.Clear();
Application.Current.Shutdown(0);
var result = Application.Current.Dispatcher.InvokeAsync(() => { }, DispatcherPriority.ContextIdle).Result;
var appCreated = typeof(Application).GetField("_appCreatedInThisAppDomain",
BindingFlags.Static |
BindingFlags.NonPublic);
appCreated.SetValue(null, false);
}
}
}
}
Base class for tests that need to use Application:
using System;
using System.Threading.Tasks;
using System.Windows.Threading;
using acme.foonav.Fixture;
namespace acme.foonav
{
public abstract class ApplicationContextTest : IDisposable
{
protected ApplicationContextTest() => ApplicationState.CreateNew();
public void Dispose() => ApplicationState.Shutdown();
protected async Task AwaitDispatcher() => await Dispatcher.CurrentDispatcher.InvokeAsync(() => { }, DispatcherPriority.ContextIdle);
}
}
A test file:
using System.Windows;
using Xunit;
namespace acme.foonav.Issues
{
public class WpfFactIssues : ApplicationContextTest
{
[WpfFact]
public void Test1()
{
TestWindow window = new TestWindow();
Assert.Equal(typeof(TestWindow), Application.Current.Windows[0]?.GetType());
}
[WpfFact]
public void Test2()
{
TestWindow window = new TestWindow();
Assert.Equal(typeof(TestWindow), Application.Current.Windows[0]?.GetType());
}
}
}
And make sure the tests don't execute in parallel:
using Xunit;
[assembly: CollectionBehavior(DisableTestParallelization = true)]

PostgreSQL and Blazor .Net Core 3.1

Are there any resources on how to use the current version of Blazor (3.1) and PostgreSQL?
I've tried writing the simplest code, just to see whether it connects to the database but I get this error message: System.Net.Dns:GetHostByName is not supported on this platform
a button click would activate this code:
async void connection()
{
var connString = "Host=Server1;Username=postgres;Password=pass;Database=BlazorData";
try
{
await using var conn = new NpgsqlConnection(connString);
await conn.OpenAsync();
errcheck = "success";
}
catch (Exception ex)
{
errcheck = ex.Message;
}
}
I explain how I use it with entity framework. It might help you.
in startup.cs, ConfigureServices method have this
services.AddEntityFrameworkNpgsql().AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")));
You need two packages to be installed through nuget
Npgsql.EntityFrameworkCore.PostgreSQL
Npgsql.EntityFrameworkCore.PostgreSQL.Design
in appsetting.json make sure you have setup connection string correctly, below one is mine. Host can be localhost if database is in the same machine as the database
"DefaultConnection": "Host=192.168.16.240;Port=5432;Username=postgres;Password=mypassword;Database=mydatabase;"
That's basically it.
then define a application db context with your tables
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions options) : base(options)
{
}
public DbSet<Room> Rooms { get; set; }
public DbSet<Meal> Meals { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
in package mangaer console
add-migration initial
update-database
you should see the tables created in PgAdmin.
and use your dbsets like usual c# lists. and remember to inject applicationdbcontext in the controllers you need it.
The error says you need to resolve the hostname by yourself. Either pass an IP address or use Dns.GetHostEntry
using System.Linq;
using System.Net;
using System.Net.Sockets;
...
async void connection()
{
var host = Dns.GetHostEntry("Server1");
var firstIpV4Address = host.AddressList.First(a => a.AddressFamily == AddressFamily.InterNetwork);
var connString = $"Host={firstIpV4Address};Username=postgres;Password=pass;Database=BlazorData";
try
{
await using var conn = new NpgsqlConnection(connString);
await conn.OpenAsync();
errcheck = "success";
}
catch (Exception ex)
{
errcheck = ex.Message;
}
}

Thucyides Test cases Queuing

Implemented A Thucydides(SERENITY) BDD Environment for automated testing of version 0.9.269. I have seen that the runner of test cases picks up the random test stories. Is there any way so that the stories can be queued?
The code for PortalTestSuit is as
public class PortalTestSuite extends ThucydidesJUnitStories {
private static final Logger LOGGER = LoggerFactory.getLogger(PortalTestSuite.class.getName());
/**
* Instantiates a new Portal test suite.
*/
public PortalTestSuite() {
/*Some Code to check the server is working or not*/
/* Do all stories */
findStoriesCalled("*.story");
}}
Here, the findStories will pick up the random stories from the directory and executes relative code... but please let me know the way to queue the Stories. Thanks.
Yes, we can maintain the order of story by overriding storyPaths() method of ThucydidesJUnitStories class.
#Override
public List<String> storyPaths() {
try {
File file = new File(System.getProperty("user.dir").concat("/src/test/resources/StoryContextTest.script"));
try (FileReader reader = new FileReader(file)) {
char[] buffer = new char[(int) file.length()];
reader.read(buffer);
String[] lines = new String(buffer).split("\n");
List<String> storiesList = new ArrayList<>(lines.length);
StoryFinder storyFinder = new StoryFinder();
for (String line : lines) {
if (!line.equals("") && !line.startsWith("#")) {
if (line.endsWith("*")) {
for (URL classpathRootUrl : allClasspathRoots()) {
storiesList.addAll(storyFinder.findPaths(classpathRootUrl, line.concat("*/*.story"), ""));
}
} else {
storiesList.add(line);
}
}
}
return storiesList;
}
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private List<URL> allClasspathRoots() {
try {
return Collections.list(getClassLoader().getResources("."));
} catch (IOException e) {
throw new IllegalArgumentException("Could not load the classpath roots when looking for story files",e);
}
}
The stories are being loaded from StoryContextTest.script as
################# Stories goes here #################
stories/authentication/authentication/authentication.story
stories/authentication/authentication/authentication1.story
(Or)
*/authentication/* (will get stories randomly)
This way you can serialize your stories as in Thucydides.

Invoke operation in wcf ria service

I use some invoke operation method in wcf ria service.like following method:
[Invoke]
public int GetCountOfAccountsByRequestId(long requestId)
{
return ObjectContext.Accounts.Count(a => a.RequestId ==requestId);
}
When i want get data from this method , i use the following code to run and get value from invoke method:
int countOfAccounts = 0;
InvokeOperation<int> invokeOperation = context.GetCountOfAccountsByRequestId(selectedRequest.RequestId);
invokeOperation.Completed += (s, args) =>
{
if (invokeOperation.HasError)
{
var messageWindow = new MessageWindow(invokeOperation.Error.Message);
messageWindow.Show();
invokeOperation.MarkErrorAsHandled();
}
else
{
countOfAccounts = invokeOperation.Value;
if (countOfAccounts == 0)
{
// do some thing
}
}
};
But this method requires a lot of coding to Run invoke method and get value from this.Also as part of this code is executed asynchronously.Similarly, some method must be implemented in tandem.And the return value of each method is related to previous methods.
How can i implement this actions?!
How can i write better than this without any problem?
For WCF RIA Services I usually create a service class in my project to handle all the interactions with the service in one place. So I would use this service class to make the calls easier to understand and use.
I put your existing code in a separate class so you can see how it might be called. Note: This is just an example. :)
public class ServiceWrapper
{
...
public void GetCountOfAccountsByRequestId(int requestId, Action<int> callback)
{
context.GetCountOfAccountsByRequestId(requestId, InvokeComplete, callback);
}
private void InvokeComplete<T>(InvokeOperation<T> io)
{
var callback = (Action<T>)io.UserState;
if (io.HasError == false)
{
callback(io.Value);
}
else
{
var messageWindow = new MessageWindow(io.Error.Message);
messageWindow.Show();
io.MarkErrorAsHandled();
}
}
}
public class YourCode
{
public void SomeMethod()
{
serviceWrapper.GetCountOfAccountsByRequestId(selectedRequest.RequestId, GetCountCompleted);
}
public void GetCountCompleted(int countOfAccounts)
{
if (countOfAccounts == 0)
{
// do some thing
}
}
}

Resources