test: Split Unit and Integration tests into separate projects (#1290)

* Squashed commit of test rewrite changes

fix missing priority speaker flag

rewrite the TestChannelPermissionModify test

add test for GuildPermission modify

separate unit and integration tests, start writing channel and guild permission tests

copy over the color tests

copy over the emote tests

copy the token utils tests

make the mocked entities sealed classes

copy the TypeReaderTests class

properly dispose the CommandService in the TypeReaderTests

start writing tests for EmbedBuilder and related classes

test that properties throw ArgumentException when invalid

add tests for the embed length property

add withFooter tests

finish adding tests to EmbedBuilder

fix bug in value validation of EmbedFieldBuilder

hey, these tests actually found a bug!

add tests for the MentionUtils class

add tests for the Format util class

remove all of the old tests

add analyzer tests (copied from old tests)

add tests for the SnowflakeUtils class

add integration tests

these get around the issue of state persisting between tests by creating and deleting a guild for each set of tests. these shouldn't be run excessively because of the rate limits, but should be fine every now and then

remove unnecessary launchSettings.json

update outdated string

don't create a new guild each time, as that can result in errors

this can happen if a bot creates too many guilds without properly deleting them

add some tests that show that guild can be modified

await async assert

add more measures that created channels are deleted when done

remove "Test" prefix from test method names

I think that this prefix when already displayed under a class with a suffix of "Tests" is redundant

Remove mention of old test project

fix an issue from forgetting to await Assert.ThrowsAsync

explicitly disable parallelization on integration tests

add test for GuildPermission modify

separate unit and integration tests, start writing channel and guild permission tests

copy over the color tests

copy over the emote tests

make the mocked entities sealed classes

properly dispose the CommandService in the TypeReaderTests

fix bug in value validation of EmbedFieldBuilder

hey, these tests actually found a bug!

add tests for the MentionUtils class

add tests for the Format util class

remove all of the old tests

add analyzer tests (copied from old tests)

add tests for the SnowflakeUtils class

add integration tests

these get around the issue of state persisting between tests by creating and deleting a guild for each set of tests. these shouldn't be run excessively because of the rate limits, but should be fine every now and then

remove unnecessary launchSettings.json

update outdated string

don't create a new guild each time, as that can result in errors

this can happen if a bot creates too many guilds without properly deleting them

add more measures that created channels are deleted when done

remove "Test" prefix from test method names

I think that this prefix when already displayed under a class with a suffix of "Tests" is redundant

Remove mention of old test project

fix an issue from forgetting to await Assert.ThrowsAsync

explicitly disable parallelization on integration tests

update the azure CI build script

separate execution of test projects so that if one fails the other will not pass

one of the unit tests failed, but the analzyer tests passed

fix test that would break in different timezones

enable the integration tests (only on dev branch)

* Squashed commit of test rewrite changes

fix missing priority speaker flag

rewrite the TestChannelPermissionModify test

add test for GuildPermission modify

separate unit and integration tests, start writing channel and guild permission tests

copy over the color tests

copy over the emote tests

copy the token utils tests

make the mocked entities sealed classes

copy the TypeReaderTests class

properly dispose the CommandService in the TypeReaderTests

start writing tests for EmbedBuilder and related classes

test that properties throw ArgumentException when invalid

add tests for the embed length property

add withFooter tests

finish adding tests to EmbedBuilder

fix bug in value validation of EmbedFieldBuilder

hey, these tests actually found a bug!

add tests for the MentionUtils class

add tests for the Format util class

remove all of the old tests

add analyzer tests (copied from old tests)

add tests for the SnowflakeUtils class

add integration tests

these get around the issue of state persisting between tests by creating and deleting a guild for each set of tests. these shouldn't be run excessively because of the rate limits, but should be fine every now and then

remove unnecessary launchSettings.json

update outdated string

don't create a new guild each time, as that can result in errors

this can happen if a bot creates too many guilds without properly deleting them

add some tests that show that guild can be modified

await async assert

add more measures that created channels are deleted when done

remove "Test" prefix from test method names

I think that this prefix when already displayed under a class with a suffix of "Tests" is redundant

Remove mention of old test project

fix an issue from forgetting to await Assert.ThrowsAsync

explicitly disable parallelization on integration tests

add test for GuildPermission modify

separate unit and integration tests, start writing channel and guild permission tests

copy over the color tests

copy over the emote tests

make the mocked entities sealed classes

properly dispose the CommandService in the TypeReaderTests

fix bug in value validation of EmbedFieldBuilder

hey, these tests actually found a bug!

add tests for the MentionUtils class

add tests for the Format util class

remove all of the old tests

add analyzer tests (copied from old tests)

add tests for the SnowflakeUtils class

add integration tests

these get around the issue of state persisting between tests by creating and deleting a guild for each set of tests. these shouldn't be run excessively because of the rate limits, but should be fine every now and then

remove unnecessary launchSettings.json

update outdated string

don't create a new guild each time, as that can result in errors

this can happen if a bot creates too many guilds without properly deleting them

add more measures that created channels are deleted when done

remove "Test" prefix from test method names

I think that this prefix when already displayed under a class with a suffix of "Tests" is redundant

Remove mention of old test project

fix an issue from forgetting to await Assert.ThrowsAsync

explicitly disable parallelization on integration tests

update the azure CI build script

separate execution of test projects so that if one fails the other will not pass

one of the unit tests failed, but the analzyer tests passed

fix test that would break in different timezones

enable the integration tests (only on dev branch)

* Update mocked channels for changed SendFileAsync signature

* comment out the integration tests from the build script

no bot token is provided to this script, and use of integration tests in CI is questionable here

* force rebuild because Azure linux build broke
This commit is contained in:
Chris Johnston
2019-06-12 13:08:03 -07:00
committed by Christopher F
parent 40844b9e13
commit a797be9ca0
49 changed files with 2326 additions and 2349 deletions

View File

@@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
namespace Discord
{
/// <summary>
/// Tests that channels can be created and modified.
/// </summary>
[CollectionDefinition("ChannelsTests", DisableParallelization = true)]
public class ChannelsTests : IClassFixture<RestGuildFixture>
{
private IGuild guild;
private readonly ITestOutputHelper output;
public ChannelsTests(RestGuildFixture guildFixture, ITestOutputHelper output)
{
guild = guildFixture.Guild;
this.output = output;
output.WriteLine($"RestGuildFixture using guild: {guild.Id}");
// capture all console output
guildFixture.Client.Log += LogAsync;
}
private Task LogAsync(LogMessage message)
{
output.WriteLine(message.ToString());
return Task.CompletedTask;
}
/// <summary>
/// Checks that a text channel can be created and modified.
/// </summary>
[Fact]
public async Task ModifyTextChannel()
{
// create a text channel to modify
var channel = await guild.CreateTextChannelAsync("text");
try
{
Assert.NotNull(channel);
// check that it can be modified
await channel.ModifyAsync(x =>
{
x.IsNsfw = true;
x.Name = "updated";
x.SlowModeInterval = 50;
x.Topic = "topic";
x.CategoryId = null;
});
// check the results of modifying this channel
Assert.True(channel.IsNsfw);
Assert.Equal("updated", channel.Name);
Assert.Equal(50, channel.SlowModeInterval);
Assert.Equal("topic", channel.Topic);
Assert.Null(channel.CategoryId);
}
finally
{
// delete the channel when finished
await channel?.DeleteAsync();
}
}
/// <summary>
/// Checks that a voice channel can be created, modified, and deleted.
/// </summary>
[Fact]
public async Task ModifyVoiceChannel()
{
var channel = await guild.CreateVoiceChannelAsync("voice");
try
{
Assert.NotNull(channel);
// try to modify it
await channel.ModifyAsync(x =>
{
x.Bitrate = 9001;
x.Name = "updated";
x.UserLimit = 1;
});
// check that these were updated
Assert.Equal(9001, channel.Bitrate);
Assert.Equal("updated", channel.Name);
Assert.Equal(1, channel.UserLimit);
}
finally
{
// delete the channel when done
await channel.DeleteAsync();
}
}
/// <summary>
/// Creates a category channel, a voice channel, and a text channel, then tries to assign them under that category.
/// </summary>
[Fact]
public async Task ModifyChannelCategories()
{
// util method for checking if a category is set
async Task CheckAsync(INestedChannel channel, ICategoryChannel cat)
{
// check that the category is not set
if (cat == null)
{
Assert.Null(channel.CategoryId);
Assert.Null(await channel.GetCategoryAsync());
}
else
{
Assert.NotNull(channel.CategoryId);
Assert.Equal(cat.Id, channel.CategoryId);
var getCat = await channel.GetCategoryAsync();
Assert.NotNull(getCat);
Assert.Equal(cat.Id, getCat.Id);
}
}
// initially create these not under the category
var category = await guild.CreateCategoryAsync("category");
var text = await guild.CreateTextChannelAsync("text");
var voice = await guild.CreateVoiceChannelAsync("voice");
try
{
Assert.NotNull(category);
Assert.NotNull(text);
Assert.NotNull(voice);
// check that the category is not set for either
await CheckAsync(text, null);
await CheckAsync(voice, null);
// set the category
await text.ModifyAsync(x => x.CategoryId = category.Id);
await voice.ModifyAsync(x => x.CategoryId = category.Id);
// check that this is set, and that it's the category that was created earlier
await CheckAsync(text, category);
await CheckAsync(voice, category);
// create one more channel immediately under this category
var newText = await guild.CreateTextChannelAsync("new-text", x => x.CategoryId = category.Id);
try
{
Assert.NotNull(newText);
await CheckAsync(newText, category);
}
finally
{
await newText?.DeleteAsync();
}
}
finally
{
// clean up
await category?.DeleteAsync();
await text?.DeleteAsync();
await voice?.DeleteAsync();
}
}
}
}

View File

@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../src/Discord.Net.Commands/Discord.Net.Commands.csproj" />
<ProjectReference Include="../../src/Discord.Net.Core/Discord.Net.Core.csproj" />
<ProjectReference Include="../../src/Discord.Net.Rest/Discord.Net.Rest.csproj" />
<ProjectReference Include="../../src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj" />
<ProjectReference Include="..\..\src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,34 @@
using Discord.Rest;
using System;
using Xunit;
namespace Discord
{
/// <summary>
/// Test fixture type for integration tests which sets up the client from
/// the token provided in environment variables.
/// </summary>
public class DiscordRestClientFixture : IDisposable
{
public DiscordRestClient Client { get; private set; }
public DiscordRestClientFixture()
{
var token = Environment.GetEnvironmentVariable("DNET_TEST_TOKEN", EnvironmentVariableTarget.Machine);
if (string.IsNullOrWhiteSpace(token))
throw new Exception("The DNET_TEST_TOKEN environment variable was not provided.");
Client = new DiscordRestClient(new DiscordRestConfig()
{
LogLevel = LogSeverity.Debug,
DefaultRetryMode = RetryMode.AlwaysRetry
});
Client.LoginAsync(TokenType.Bot, token).Wait();
}
public void Dispose()
{
Client.LogoutAsync().Wait();
Client.Dispose();
}
}
}

View File

@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
namespace Discord
{
[CollectionDefinition("GuildTests", DisableParallelization = true)]
public class GuildTests : IClassFixture<RestGuildFixture>
{
private IDiscordClient client;
private IGuild guild;
private readonly ITestOutputHelper output;
public GuildTests(RestGuildFixture guildFixture, ITestOutputHelper output)
{
client = guildFixture.Client;
guild = guildFixture.Guild;
this.output = output;
output.WriteLine($"RestGuildFixture using guild: {guild.Id}");
guildFixture.Client.Log += LogAsync;
}
private Task LogAsync(LogMessage message)
{
output.WriteLine(message.ToString());
return Task.CompletedTask;
}
/// <summary>
/// Ensures that the CurrentUser is the owner of the guild.
/// </summary>
[Fact]
public void CheckOwner()
{
Assert.Equal(client.CurrentUser.Id, guild.OwnerId);
}
/// <summary>
/// Checks that a Guild can be modified to non-default values.
/// </summary>
[Fact]
public async Task ModifyGuild()
{
// set some initial properties of the guild that are not the defaults
await guild.ModifyAsync(x =>
{
x.ExplicitContentFilter = ExplicitContentFilterLevel.AllMembers;
x.Name = "updated";
x.DefaultMessageNotifications = DefaultMessageNotifications.MentionsOnly;
x.AfkTimeout = 900; // 15 minutes
x.VerificationLevel = VerificationLevel.None;
});
// check that they were set
Assert.Equal("updated", guild.Name);
Assert.Equal(ExplicitContentFilterLevel.AllMembers, guild.ExplicitContentFilter);
Assert.Equal(DefaultMessageNotifications.MentionsOnly, guild.DefaultMessageNotifications);
Assert.Equal(VerificationLevel.None, guild.VerificationLevel);
Assert.Equal(900, guild.AFKTimeout);
}
/// <summary>
/// Checks that the SystemChannel property of a guild can be modified.
/// </summary>
[Fact]
public async Task ModifySystemChannel()
{
var systemChannel = await guild.CreateTextChannelAsync("system");
// set using the Id
await guild.ModifyAsync(x => x.SystemChannelId = systemChannel.Id);
Assert.Equal(systemChannel.Id, guild.SystemChannelId);
// unset it
await guild.ModifyAsync(x => x.SystemChannelId = null);
Assert.Null(guild.SystemChannelId);
Assert.Null(await guild.GetSystemChannelAsync());
// set using the ITextChannel
await guild.ModifyAsync(x => { x.SystemChannel = new Optional<ITextChannel>(systemChannel); });
Assert.Equal(systemChannel.Id, guild.SystemChannelId);
await Assert.ThrowsAsync<NullReferenceException>( async () =>
{
await guild.ModifyAsync(x => x.SystemChannel = null);
});
await systemChannel.DeleteAsync();
}
/// <summary>
/// Checks that the AFK channel of a guild can be set.
/// </summary>
[Fact]
public async Task ModifyAfkChannel()
{
var afkChannel = await guild.CreateVoiceChannelAsync("afk");
// set using the Id
await guild.ModifyAsync(x => x.AfkChannelId = afkChannel.Id);
Assert.Equal(afkChannel.Id, guild.AFKChannelId);
// unset using Id
await guild.ModifyAsync(x => x.AfkChannelId = null);
Assert.Null(guild.AFKChannelId);
Assert.Null(await guild.GetAFKChannelAsync());
// the same, but with the AfkChannel property
await guild.ModifyAsync(x => x.AfkChannel = new Optional<IVoiceChannel>(afkChannel));
Assert.Equal(afkChannel.Id, guild.AFKChannelId);
await Assert.ThrowsAsync<NullReferenceException>( async () =>
{
await guild.ModifyAsync(x => x.AfkChannel = null);
});
await afkChannel.DeleteAsync();
}
}
}

View File

@@ -0,0 +1,44 @@
using Discord.Rest;
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace Discord
{
/// <summary>
/// Gets or creates a guild to use for testing.
/// </summary>
public class RestGuildFixture : DiscordRestClientFixture
{
public RestGuild Guild { get; private set; }
public RestGuildFixture() : base()
{
var guilds = Client.GetGuildsAsync().Result.Where(x => x.OwnerId == Client.CurrentUser.Id).ToList();
if (guilds.Count == 0)
{
// create a new guild if none exists already
var region = Client.GetOptimalVoiceRegionAsync().Result;
Guild = Client.CreateGuildAsync("DNET INTEGRATION TEST", region).Result;
RemoveAllChannels();
}
else
{
// get the first one if there is a guild already created
Guild = guilds.First();
}
}
/// <summary>
/// Removes all channels in the guild.
/// </summary>
private void RemoveAllChannels()
{
foreach (var channel in Guild.GetChannelsAsync().Result)
{
channel.DeleteAsync().Wait();
}
}
}
}