diff --git a/FileSender/Solved/FileSender_Should.cs b/FileSender/Solved/FileSender_Should.cs index 050c299..c138e35 100644 --- a/FileSender/Solved/FileSender_Should.cs +++ b/FileSender/Solved/FileSender_Should.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Security.Cryptography.X509Certificates; using FakeItEasy; using FileSender.Dependencies; @@ -20,10 +20,10 @@ public class FileSender_Should [SetUp] public void SetUp() { - // - // -. - // , , - // "" + // Тут мы задаем некоторые известны для всех тестов данные + // и умолчательные поведения сервисов-заглушек. + // Наша цель — сделать так, чтобы в конкретных тестах осталась только их специфика, + // а конфигурирование "обычного" поведения не надо было повторять от теста к тесту cryptographer = A.Fake(); sender = A.Fake(); recognizer = A.Fake(); @@ -73,7 +73,7 @@ public void Skip_WhenOlderThanAMonth() [Test] public void Skip_WhenSendFails() { - var someFile = CreateSomeGoodDocumnetFile(); + var someFile = CreateSomeGoodDocumentFile(); A.CallTo(() => sender.TrySend(null)) .WithAnyArguments().Returns(false); @@ -84,7 +84,7 @@ public void Skip_WhenSendFails() [Test] public void Skip_WhenNotRecognized() { - var file = CreateSomeGoodDocumnetFile(); + var file = CreateSomeGoodDocumentFile(); Document document; A.CallTo(() => recognizer.TryRecognize(file, out document)) .Returns(false); @@ -94,9 +94,9 @@ public void Skip_WhenNotRecognized() [Test] public void IndependentlySendSeveralFiles_WhenSomeFailedToSend() { - var file1 = CreateSomeGoodDocumnetFile(); - var file2 = CreateSomeGoodDocumnetFile(); - var file3 = CreateSomeGoodDocumnetFile(); + var file1 = CreateSomeGoodDocumentFile(); + var file2 = CreateSomeGoodDocumentFile(); + var file3 = CreateSomeGoodDocumentFile(); A.CallTo(() => sender.TrySend(A.Ignored)) .ReturnsNextFromSequence(false, true, false); @@ -110,9 +110,9 @@ public void IndependentlySendSeveralFiles_WhenSomeFailedToSend() [Test] public void IndependentlySendSeveralFiles_WhenSomeCantBeRecognized() { - var file1 = CreateSomeGoodDocumnetFile(); - var file2 = CreateSomeGoodDocumnetFile(); - var file3 = CreateSomeGoodDocumnetFile(); + var file1 = CreateSomeGoodDocumentFile(); + var file2 = CreateSomeGoodDocumentFile(); + var file3 = CreateSomeGoodDocumentFile(); Document document; A.CallTo(() => recognizer.TryRecognize(file2, out document)) @@ -126,7 +126,7 @@ public void IndependentlySendSeveralFiles_WhenSomeCantBeRecognized() .MustHaveHappened(Repeated.Exactly.Twice); } - private File CreateSomeGoodDocumnetFile() + private File CreateSomeGoodDocumentFile() { return CreateDocumentFile(DateTime.Now); } diff --git a/ThingCache/Challenge/IncorrectImplementations/DoNotOpen.cs b/ThingCache/Challenge/IncorrectImplementations/DoNotOpen.cs new file mode 100644 index 0000000..5ba6a35 --- /dev/null +++ b/ThingCache/Challenge/IncorrectImplementations/DoNotOpen.cs @@ -0,0 +1,304 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Challenge.Infrastructure; +using MockFramework; + +namespace Challenge.IncorrectImplementations +{ + #region Не подглядывать! + + // [IncorrectImplementation] + public abstract class ThingCacheBase : IThingCache + { + protected readonly IThingService thingService; + protected IDictionary dictionary = new Dictionary(); + + protected ThingCacheBase(IThingService thingService) + { + this.thingService = thingService; + } + + public virtual Thing Get(string thingId) + { + Thing thing; + if (dictionary.TryGetValue(thingId, out thing)) + return thing; + if (thingService.TryRead(thingId, out thing)) + { + dictionary[thingId] = thing; + return thing; + } + return null; + } + } + + public abstract class ThingCacheWithCapacity : ThingCacheBase + { + protected abstract int CacheSize { get; } + private readonly Queue> cache = new Queue>(); + + public ThingCacheWithCapacity(IThingService thingService) + : base(thingService) + { + } + + public override Thing Get(string thingId) + { + var kvp = cache.FirstOrDefault(x => x.Key == thingId); + if (kvp.Value != null) + return kvp.Value; + + Thing thing; + if (!thingService.TryRead(thingId, out thing) || thing == null) + return null; + cache.Enqueue(new KeyValuePair(thingId, thing)); + if (cache.Count > CacheSize) + cache.Dequeue(); + return thing; + } + } + + [IncorrectImplementation("Ничего не кэширует")] + public class ThingCache0 : ThingCacheWithCapacity + { + public ThingCache0(IThingService thingService) + : base(thingService) + { + } + + protected override int CacheSize { get; } = 0; + } + + [IncorrectImplementation("Размер кэша - 1 элемент")] + public class ThingCache1 : ThingCacheWithCapacity + { + public ThingCache1(IThingService thingService) + : base(thingService) + { + } + + protected override int CacheSize { get; } = 1; + } + + [IncorrectImplementation("Размер кэша - 2 элемента")] + public class ThingCache2 : ThingCacheWithCapacity + { + public ThingCache2(IThingService thingService) + : base(thingService) + { + } + + protected override int CacheSize { get; } = 2; + } + + [IncorrectImplementation("Размер кэша - 3 элемента")] + public class ThingCache3 : ThingCacheWithCapacity + { + public ThingCache3(IThingService thingService) + : base(thingService) + { + } + + protected override int CacheSize { get; } = 3; + } + + [IncorrectImplementation("Не проверяет, вернул ли ThingService осмысленный результат")] + public class ThingCacheAll : ThingCacheBase + { + public ThingCacheAll(IThingService thingService) + : base(thingService) + { + } + + public override Thing Get(string thingId) + { + Thing thing; + if (dictionary.TryGetValue(thingId, out thing)) + return thing; + thingService.TryRead(thingId, out thing); + dictionary[thingId] = thing; + return thing; + } + } + + [IncorrectImplementation("Не учитывает регистр ключей")] + public class ThingCacheCase : ThingCacheBase + { + public ThingCacheCase(IThingService thingService) + : base(thingService) + { + dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + } + + [IncorrectImplementation("Возвращает Thing с пустым именем вместо null")] + public class ThingCacheEmpty : ThingCacheBase + { + private new readonly IDictionary dictionary + = new Dictionary(); + + public ThingCacheEmpty(IThingService thingService) + : base(thingService) + { + } + + public override Thing Get(string thingId) + { + Thing thing; + if (dictionary.TryGetValue(thingId, out thing)) + return thing; + if (thingService.TryRead(thingId, out thing)) + { + dictionary[thingId] = thing; + return thing; + } + return new Thing(string.Empty); + } + } + + [IncorrectImplementation("Возвращает Thing с именем null вместо Thing == null")] + public class ThingCacheNull : ThingCacheBase + { + private new readonly IDictionary dictionary + = new Dictionary(); + + public ThingCacheNull(IThingService thingService) + : base(thingService) + { + } + + public override Thing Get(string thingId) + { + Thing thing; + if (dictionary.TryGetValue(thingId, out thing)) + return thing; + if (thingService.TryRead(thingId, out thing)) + { + dictionary[thingId] = thing; + return thing; + } + return new Thing(string.Empty); + } + } + + [IncorrectImplementation("Кэширует одно (первое) значение для всех")] + public class ThingCacheSingle : ThingCacheBase + { + private Thing cachedThing; + + public ThingCacheSingle(IThingService thingService) + : base(thingService) + { + } + + public override Thing Get(string thingId) + { + Thing thing; + if (cachedThing != null) + return cachedThing; + if (thingService.TryRead(thingId, out thing)) + { + cachedThing = thing; + return thing; + } + return null; + } + } + + [IncorrectImplementation("Кэширует одно (последнее) значение для всех")] + public class ThingCacheSingle2 : ThingCacheBase + { + private Thing cachedThing; + private HashSet cachedKeys = new HashSet(); + + public ThingCacheSingle2(IThingService thingService) + : base(thingService) + { + } + + public override Thing Get(string thingId) + { + Thing thing; + if (cachedKeys.Contains(thingId) && cachedThing != null) + return cachedThing; + if (thingService.TryRead(thingId, out thing)) + { + cachedKeys.Add(thingId); + cachedThing = thing; + return thing; + } + return null; + } + } + + [IncorrectImplementation("Дважды запрашивает thing у ThingService")] + public class ThingCacheTwice : ThingCacheBase + { + public ThingCacheTwice(IThingService thingService) + : base(thingService) + { + } + + public override Thing Get(string thingId) + { + Thing thing; + if (dictionary.TryGetValue(thingId, out thing)) + return thing; + if (thingService.TryRead(thingId, out thing)) + { + thingService.TryRead(thingId, out thing); + dictionary[thingId] = thing; + return thing; + } + return null; + } + } + + [IncorrectImplementation("Удаляет элементы из кэша при обращении")] + public class ThingCacheRem : ThingCacheBase + { + public ThingCacheRem(IThingService thingService) + : base(thingService) + { + } + + public override Thing Get(string thingId) + { + var remove = dictionary.ContainsKey(thingId); + var thing = base.Get(thingId); + if (remove) + dictionary.Remove(thingId); + return thing; + } + } + + [IncorrectImplementation("Статический кэш")] + public class ThingCacheSTA : ThingCacheBase + { + private new static readonly IDictionary dictionary + = new Dictionary(); + + public ThingCacheSTA(IThingService thingService) + : base(thingService) + { + dictionary.Clear(); + } + + public override Thing Get(string thingId) + { + Thing thing; + if (dictionary.TryGetValue(thingId, out thing)) + return thing; + if (thingService.TryRead(thingId, out thing)) + { + dictionary[thingId] = thing; + return thing; + } + return null; + } + } + + + #endregion +} \ No newline at end of file diff --git a/ThingCache/Challenge/Infrastructure/ChallengeHelpers.cs b/ThingCache/Challenge/Infrastructure/ChallengeHelpers.cs new file mode 100644 index 0000000..1371246 --- /dev/null +++ b/ThingCache/Challenge/Infrastructure/ChallengeHelpers.cs @@ -0,0 +1,40 @@ +using System; +using System.Linq; +using System.Reflection; +using MockFramework; + +namespace Challenge.Infrastructure +{ + public static class ChallengeHelpers + { + public static Type[] GetIncorrectImplementationTypes() + { + return GetInheritorsOf() + .Where(t => t.HasAttribute()) + .OrderBy(t => t.Name.Length).ThenBy(t => t.Name) + .ToArray(); + } + + public static IncorrectImplementation_TestsBase[] GetIncorrectImplementationTests() + { + return GetInheritorsOf() + .Select(Activator.CreateInstance) + .Cast() + .ToArray(); + } + + public static bool HasAttribute(this Type method) where TAttribute : Attribute + { + return method.GetCustomAttributes(typeof(TAttribute), true).Any(); + } + + public static Type[] GetInheritorsOf() + { + var baseType = typeof(T); + return Assembly.GetExecutingAssembly().GetTypes() + .Where(baseType.IsAssignableFrom) + .Where(t => t != baseType && !t.IsAbstract && !t.IsInterface) + .ToArray(); + } + } +} \ No newline at end of file diff --git a/ThingCache/Challenge/Infrastructure/Firebase.cs b/ThingCache/Challenge/Infrastructure/Firebase.cs new file mode 100644 index 0000000..0fbae87 --- /dev/null +++ b/ThingCache/Challenge/Infrastructure/Firebase.cs @@ -0,0 +1,27 @@ +using System; +using FireSharp; +using FireSharp.Config; + +namespace Challenge.Infrastructure +{ + public static class Firebase + { + private static FirebaseConfig BuildConfig() + { + const string Url = "https://mocks-challenge.firebaseio.com/"; + const string Realm = "thingcache"; + var dateKey = DateTime.Now.Date.ToString("yyyyMMdd"); + + var config = new FirebaseConfig + { + BasePath = $"{Url}/{Realm}/{dateKey}" + }; + return config; + } + + public static FirebaseClient CreateClient() + { + return new FirebaseClient(BuildConfig()); + } + } +} \ No newline at end of file diff --git a/ThingCache/Challenge/Infrastructure/FirebaseActions.cs b/ThingCache/Challenge/Infrastructure/FirebaseActions.cs new file mode 100644 index 0000000..b6993f3 --- /dev/null +++ b/ThingCache/Challenge/Infrastructure/FirebaseActions.cs @@ -0,0 +1,24 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NUnit.Framework; + +namespace Challenge.Infrastructure +{ + [TestFixture] + public class FirebaseActions + { + [Test, Explicit] + public void ClearLeaderboard() + { + using (var client = Firebase.CreateClient()) + { + var response = client.Get(""); + var jObject = (JObject)JsonConvert.DeserializeObject(response.Body); + foreach (var pair in jObject) + { + client.Delete(pair.Key); + } + } + } + } +} \ No newline at end of file diff --git a/ThingCache/Challenge/Infrastructure/ImplementationStatus.cs b/ThingCache/Challenge/Infrastructure/ImplementationStatus.cs new file mode 100644 index 0000000..6829128 --- /dev/null +++ b/ThingCache/Challenge/Infrastructure/ImplementationStatus.cs @@ -0,0 +1,14 @@ +namespace Challenge.Infrastructure +{ + public class ImplementationStatus + { + public ImplementationStatus(string name, string[] fails) + { + Name = name; + Fails = fails; + } + + public readonly string Name; + public readonly string[] Fails; + } +} \ No newline at end of file diff --git a/ThingCache/Challenge/Infrastructure/IncorrectImplementationAttribute.cs b/ThingCache/Challenge/Infrastructure/IncorrectImplementationAttribute.cs new file mode 100644 index 0000000..bb7246d --- /dev/null +++ b/ThingCache/Challenge/Infrastructure/IncorrectImplementationAttribute.cs @@ -0,0 +1,11 @@ +using System; + +namespace Challenge.Infrastructure +{ + public class IncorrectImplementationAttribute : Attribute + { + public IncorrectImplementationAttribute(string description) + { + } + } +} \ No newline at end of file diff --git a/ThingCache/Challenge/Infrastructure/IncorrectImplementation_TestsBase.cs b/ThingCache/Challenge/Infrastructure/IncorrectImplementation_TestsBase.cs new file mode 100644 index 0000000..9f4d24d --- /dev/null +++ b/ThingCache/Challenge/Infrastructure/IncorrectImplementation_TestsBase.cs @@ -0,0 +1,21 @@ +using System; +using Challenge.IncorrectImplementations; +using MockFramework; +using NUnit.Framework; + +namespace Challenge.Infrastructure +{ + public abstract class IncorrectImplementation_TestsBase : ThingCache_Should + { + public override IThingCache CreateThingCache(IThingService thingService) + { + string ns = typeof(ThingCacheBase).Namespace; + var implTypeName = ns + "." + GetType().Name.Replace("_Should", ""); + var implType = GetType().Assembly.GetType(implTypeName); + if (implType == null) + Assert.Fail("no type {0}", implTypeName); + return (IThingCache)Activator.CreateInstance(implType, thingService); + } + } +} + diff --git a/ThingCache/Challenge/Infrastructure/IncorrectImplementations_Tests.cs b/ThingCache/Challenge/Infrastructure/IncorrectImplementations_Tests.cs new file mode 100644 index 0000000..80602f0 --- /dev/null +++ b/ThingCache/Challenge/Infrastructure/IncorrectImplementations_Tests.cs @@ -0,0 +1,38 @@ +using System; +using System.Linq; +using NUnit.Framework; + +namespace Challenge.Infrastructure +{ + [TestFixture] + public class GenerateIncorrectTests + { + [Test] + public void Generate() + { + var impls = ChallengeHelpers.GetIncorrectImplementationTypes(); + var code = string.Join(Environment.NewLine, + impls.Select(imp => $"public class {imp.Name}_Tests : {nameof(IncorrectImplementation_TestsBase)} {{}}") + ); + Console.WriteLine(code); + } + } + + #region Generated with test above + + public class ThingCache0_Should : IncorrectImplementation_TestsBase { } + public class ThingCache1_Should : IncorrectImplementation_TestsBase { } + public class ThingCache2_Should : IncorrectImplementation_TestsBase { } + public class ThingCache3_Should : IncorrectImplementation_TestsBase { } + public class ThingCacheAll_Should : IncorrectImplementation_TestsBase { } + public class ThingCacheCase_Should : IncorrectImplementation_TestsBase { } + public class ThingCacheEmpty_Should : IncorrectImplementation_TestsBase { } + public class ThingCacheNull_Should : IncorrectImplementation_TestsBase { } + public class ThingCacheSingle_Should : IncorrectImplementation_TestsBase { } + public class ThingCacheSingle2_Should : IncorrectImplementation_TestsBase { } + public class ThingCacheTwice_Should : IncorrectImplementation_TestsBase { } + public class ThingCacheRem_Should : IncorrectImplementation_TestsBase { } + public class ThingCacheSTA_Should : IncorrectImplementation_TestsBase { } + + #endregion +} \ No newline at end of file diff --git a/ThingCache/Challenge/Infrastructure/Program.cs b/ThingCache/Challenge/Infrastructure/Program.cs new file mode 100644 index 0000000..29e3e64 --- /dev/null +++ b/ThingCache/Challenge/Infrastructure/Program.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Xml; +using MockFramework; +using NUnit.Engine; + +namespace Challenge.Infrastructure +{ + internal class Program + { + private static void Main() + { + if (ThingCache_Should.Authors == "<ВАШИ ФАМИЛИИ>") + { + Console.WriteLine("Укажите ваши фамилии в классе ThingCache_Should в поле Authors!"); + Thread.Sleep(5000); + return; + } + var testPackage = new TestPackage(Assembly.GetExecutingAssembly().Location); + using (var engine = new TestEngine()) + using (var testRunner = engine.GetRunner(testPackage)) + if (TestsAreValid(testRunner)) + { + var incorrectImplementations = ChallengeHelpers.GetIncorrectImplementationTypes(); + var statuses = GetIncorrectImplementationsResults(testRunner, incorrectImplementations); + var res = new List(); + foreach (var status in statuses) + { + res.Add(status); + WriteImplementationStatusToConsole(status); + } + PostResults(res); + } + } + + private static void PostResults(IList statuses) + { + try + { + using (var client = Firebase.CreateClient()) + { + string authorsKey = MakeFirebaseSafe(ThingCache_Should.Authors); + var values = statuses.Select(s => s.Fails.Length).ToArray(); + //client.Set(authorsKey + "/implementations", values); + client.Set(authorsKey, new + { + implementations = values, + time = DateTime.Now.ToUniversalTime() + }); + } + Console.WriteLine(""); + } + catch(Exception e) + { + Console.WriteLine(e.Message); + } + } + + private static string MakeFirebaseSafe(string s) + { + var badChars = Enumerable.Range(0, 32).Select(code => (char)code) + .Concat(".$#[]/" + (char)127); + foreach (var badChar in badChars) + s = s.Replace(badChar, '_'); + return s; + } + + private static IEnumerable GetIncorrectImplementationsResults( + ITestRunner testRunner, IEnumerable implementations) + { + var implTypeToTestsType = ChallengeHelpers.GetIncorrectImplementationTests() + .ToDictionary(t => t.CreateThingCache(null).GetType(), t => t.GetType()); + foreach (var implementation in implementations) + { + var failed = GetFailedTests(testRunner, + implementation, + implTypeToTestsType[implementation]) + .ToArray(); + yield return new ImplementationStatus(implementation.Name, failed); + } + } + + private static void WriteImplementationStatusToConsole(ImplementationStatus status) + { + var paddedName = status.Name.PadRight(20, ' '); + if (status.Fails.Any()) + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine(TrimToConsole(paddedName + "fails on: " + string.Join(", ", status.Fails))); + Console.ForegroundColor = ConsoleColor.Gray; + } + else + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(paddedName + "write some test to kill it"); + Console.ForegroundColor = ConsoleColor.Gray; + } + } + + private static string TrimToConsole(string text) + { + try + { + var w = Console.WindowWidth - 1; + return text.Length > w ? text.Substring(0, w) : text; + } + catch (IOException) + { + return text; + } + } + + private static bool TestsAreValid(ITestRunner testRunner) + { + Console.WriteLine("Check all tests pass with correct implementation..."); + var failed = GetFailedTests(testRunner, + typeof(ThingCache), + typeof(ThingCache_Should)) + .ToList(); + if (failed.Any()) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Incorrect tests detected: " + string.Join(", ", failed) + Environment.NewLine + "Check SetUp method first!"); + Console.ForegroundColor = ConsoleColor.Gray; + return false; + } + else + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("Tests are OK!"); + Console.ForegroundColor = ConsoleColor.Gray; + return true; + } + } + + private static IEnumerable GetFailedTests(ITestRunner testRunner, + Type implementationType, Type testsType) + { + var builder = new TestFilterBuilder(); + builder.AddTest(testsType.FullName); + var report = testRunner.Run(null, builder.GetFilter()); + Debug.Assert(report != null); + File.WriteAllText($"{implementationType.Name}.nunitReport.xml", report.OuterXml); + var failedTestCases = report.SelectNodes("//test-case[@result='Failed']"); + Debug.Assert(failedTestCases != null); + foreach (var xmlNode in failedTestCases.Cast()) + { + Debug.Assert(xmlNode.Attributes != null); + yield return xmlNode.Attributes["name"].Value; + } + } + } +} \ No newline at end of file diff --git a/ThingCache/IThingCache.cs b/ThingCache/IThingCache.cs new file mode 100644 index 0000000..c7385c0 --- /dev/null +++ b/ThingCache/IThingCache.cs @@ -0,0 +1,7 @@ +namespace MockFramework +{ + public interface IThingCache + { + Thing Get(string thingId); + } +} \ No newline at end of file diff --git a/ThingCache/Solved/ThingCache_Should.cs b/ThingCache/Solved/ThingCache_Should.cs index e25be04..641f22c 100644 --- a/ThingCache/Solved/ThingCache_Should.cs +++ b/ThingCache/Solved/ThingCache_Should.cs @@ -7,19 +7,26 @@ namespace MockFramework.Solved public class ThingCache_Should { private IThingService thingService; - private ThingCache thingCache; + private IThingCache thingCache; private const string thingId1 = "TheDress"; private Thing thing1 = new Thing(thingId1); private const string thingId2 = "CoolBoots"; private Thing thing2 = new Thing(thingId2); + + public static string Authors = "<ВАШИ ФАМИЛИИ>"; // e.g. "Zharkov Peshkov" + + public virtual IThingCache CreateThingCache(IThingService thingService) + { + return new ThingCache(thingService); + } [SetUp] public void SetUp() { thingService = A.Fake(); - thingCache = new ThingCache(thingService); + thingCache = CreateThingCache(thingService); } [Test] diff --git a/ThingCache/Solved/ThingCache_Tests.cs b/ThingCache/Solved/ThingCache_Tests.cs index f73fd54..a948240 100644 --- a/ThingCache/Solved/ThingCache_Tests.cs +++ b/ThingCache/Solved/ThingCache_Tests.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using FakeItEasy; using FluentAssertions; using NUnit.Framework; @@ -8,7 +9,7 @@ namespace MockFramework public class ThingCache_Tests { private IThingService thingService; - private ThingCache thingCache; + private IThingCache thingCache; private const string thingId1 = "TheDress"; private Thing thing1 = new Thing(thingId1); @@ -16,11 +17,18 @@ public class ThingCache_Tests private const string thingId2 = "CoolBoots"; private Thing thing2 = new Thing(thingId2); + public static string Authors = "<ВАШИ ФАМИЛИИ>"; // e.g. "Zharkov Peshkov" + + public virtual IThingCache CreateThingCache(IThingService thingService) + { + return new ThingCache(thingService); + } + [SetUp] public void SetUp() { thingService = A.Fake(); - thingCache = new ThingCache(thingService); + thingCache = CreateThingCache(thingService); } [Test] diff --git a/ThingCache/ThingCache.cs b/ThingCache/ThingCache.cs index 81a1866..17fcc52 100644 --- a/ThingCache/ThingCache.cs +++ b/ThingCache/ThingCache.cs @@ -1,53 +1,61 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NUnit.Framework; namespace MockFramework { - public class ThingCache - { - private readonly IDictionary dictionary - = new Dictionary(); - private readonly IThingService thingService; - - public ThingCache(IThingService thingService) - { - this.thingService = thingService; - } - - public Thing Get(string thingId) - { - Thing thing; - if (dictionary.TryGetValue(thingId, out thing)) - return thing; - if (thingService.TryRead(thingId, out thing)) - { - dictionary[thingId] = thing; - return thing; - } - return null; - } - } - - [TestFixture] - public class ThingCache_Should - { - private IThingService thingService; - private ThingCache thingCache; - - private const string thingId1 = "TheDress"; - private Thing thing1 = new Thing(thingId1); - - private const string thingId2 = "CoolBoots"; - private Thing thing2 = new Thing(thingId2); - - [SetUp] - public void SetUp() - { - //thingService = A... - thingCache = new ThingCache(thingService); - } - - //TODO: , - //Live Template tt ! - } + public class ThingCache : IThingCache + { + private readonly IDictionary dictionary + = new Dictionary(); + private readonly IThingService thingService; + + public ThingCache(IThingService thingService) + { + this.thingService = thingService; + } + + public Thing Get(string thingId) + { + Thing thing; + if (dictionary.TryGetValue(thingId, out thing)) + return thing; + if (thingService.TryRead(thingId, out thing)) + { + dictionary[thingId] = thing; + return thing; + } + return null; + } + } + + [TestFixture] + public class ThingCache_Should + { + private IThingService thingService; + private IThingCache thingCache; + + private const string thingId1 = "TheDress"; + private Thing thing1 = new Thing(thingId1); + + private const string thingId2 = "CoolBoots"; + private Thing thing2 = new Thing(thingId2); + + public static string Authors = "<ВАШИ ФАМИЛИИ>"; // e.g. "Zharkov Peshkov" + + public virtual IThingCache CreateThingCache(IThingService thingService) + { + // переопределяется при запуске exe + return new ThingCache(thingService); + } + + [SetUp] + public void SetUp() + { + //thingService = A... + thingCache = CreateThingCache(thingService); + } + + //TODO: написать простейший тест, а затем все остальные + //Live Template tt работает! + } } \ No newline at end of file diff --git a/ThingCache/ThingCache.csproj b/ThingCache/ThingCache.csproj index bd22f81..d3a887b 100644 --- a/ThingCache/ThingCache.csproj +++ b/ThingCache/ThingCache.csproj @@ -5,7 +5,7 @@ Debug AnyCPU {DF0A47D1-7D8B-4511-B997-C4C7EF4ADD29} - Library + Exe Properties MockFramework MockFramework @@ -41,6 +41,9 @@ ..\packages\FakeItEasy.1.25.3\lib\net40\FakeItEasy.dll True + + ..\packages\FireSharp.2.0.4\lib\portable-net45+sl5+wp8+win8\FireSharp.dll + ..\packages\FluentAssertions.4.16.0\lib\net45\FluentAssertions.dll True @@ -49,12 +52,44 @@ ..\packages\FluentAssertions.4.16.0\lib\net45\FluentAssertions.Core.dll True - - ..\packages\NUnit.2.6.4\lib\nunit.framework.dll - True + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + + + ..\packages\NUnit.Engine.3.7.0\lib\Mono.Cecil.dll + + + ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll + + + ..\packages\NUnit.Engine.3.7.0\lib\nunit-agent.exe + + + ..\packages\NUnit.Engine.3.7.0\lib\nunit-agent-x86.exe + + + ..\packages\NUnit.Engine.3.7.0\lib\nunit.engine.dll + + + ..\packages\NUnit.Engine.3.7.0\lib\nunit.engine.api.dll + + + ..\packages\NUnit.3.9.0\lib\net45\nunit.framework.dll + + ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll + + + ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll + @@ -63,6 +98,16 @@ + + + + + + + + + + diff --git a/ThingCache/leaderboard.html b/ThingCache/leaderboard.html new file mode 100644 index 0000000..7675c30 --- /dev/null +++ b/ThingCache/leaderboard.html @@ -0,0 +1,62 @@ + + + + + + + +
+ + + + diff --git a/ThingCache/packages.config b/ThingCache/packages.config index 5722e18..c06b1fc 100644 --- a/ThingCache/packages.config +++ b/ThingCache/packages.config @@ -1,6 +1,19 @@  + - + + + + + + + + + + + + + \ No newline at end of file